Problem
TruthTable::from_outputs() requires exactly 2^num_inputs output values, but the custom Deserialize implementation constructs TruthTable directly and bypasses that invariant.
A small malformed value such as:
{"num_inputs": 2, "outputs": [true]}
deserializes successfully. Later operations assume four rows and may index past the stored output vector.
Root cause
The deserialization boundary duplicates construction instead of applying the type invariant. As a result, serialized input can create states that the public constructor rejects.
The expected-length calculation also uses an unchecked native shift, so an unrepresentable 2^num_inputs can panic before a useful deserialization error is produced.
Required behavior
- Deserialization must reject any output length other than exactly
2^num_inputs.
- If
2^num_inputs is not representable as usize, deserialization must return an explicit error.
- Valid serialized truth tables must retain the current representation and round-trip behavior.
- Do not add compatibility handling for malformed tables.
Keep the invariant in one construction path or perform the same direct validation at the deserialization boundary; do not add a generic validation framework.
Verification
Add focused tests proving:
{"num_inputs":2,"outputs":[true]} is rejected;
- both short and extra output vectors are rejected;
- an unrepresentable row count returns a deserialization error without panicking;
- a valid truth table still round-trips and evaluates every row correctly.
Run make check.
Problem
TruthTable::from_outputs()requires exactly2^num_inputsoutput values, but the customDeserializeimplementation constructsTruthTabledirectly and bypasses that invariant.A small malformed value such as:
{"num_inputs": 2, "outputs": [true]}deserializes successfully. Later operations assume four rows and may index past the stored output vector.
Root cause
The deserialization boundary duplicates construction instead of applying the type invariant. As a result, serialized input can create states that the public constructor rejects.
The expected-length calculation also uses an unchecked native shift, so an unrepresentable
2^num_inputscan panic before a useful deserialization error is produced.Required behavior
2^num_inputs.2^num_inputsis not representable asusize, deserialization must return an explicit error.Keep the invariant in one construction path or perform the same direct validation at the deserialization boundary; do not add a generic validation framework.
Verification
Add focused tests proving:
{"num_inputs":2,"outputs":[true]}is rejected;Run
make check.