Represent sub-binaries down to the bit: the trailing-bit count (0..7) is
packed into the low 3 bits of the sub-binary offset word, so the box stays
4 words wide and memory.c is untouched. Bit syntax construction and
matching (including the legacy no_bs_create_bin opcodes emitted by OTP
26-27), binary_to_list/1, bitstring_to_list/1, is_bitstring/1, term
printing and the external term format all handle bitstrings that are not a
whole number of bytes.
Reject segment sizes that would wrap before they are scaled or accumulated:
in bs_create_bin (interpreter and JIT) and the dynamic bs_get_binary2 JIT
match path, a size * unit product or a running total that overflows now
fails (badarg/system_limit on construction, nomatch on matching) instead of
wrapping to a small value that passes the capacity check. The JIT reuses an
overflow-aware scaler on all match and construction paths.
Sign-extend integers narrower than the field but wider than 64 bits: a
negative value fills the high bits with 1s (big and little endian) rather
than zero-extending. Reject a non-byte-aligned big integer written by the
legacy bs_put_integer opcode, as bs_create_bin already does.
In the JIT integer extraction, check the remaining capacity before
rejecting a >64-bit field as unsupported: an oversize dynamic segment size
fails the match (nope), as on BEAM and as the interpreter already does,
rather than raising.
Widen the BIT_BINARY_EXT length before adding it to the base size on both
external-term decode paths, so the consumed size does not wrap in 32-bit
arithmetic, and return the serialized size as size_t.
Move the big-integer decode of the external term format into a NOINLINE
helper (parse_bigint): its INTN_MAX_RES_LEN stack buffer (~1KB) otherwise
inflated every recursive parse_external_terms frame, overflowing the
scheduler stack when loading a module with a deeply nested literal.
Drop the unreachable register-size case of the bs_match integer command in
the JIT and interpreter, and remove the now-unused term_bs_insert_binary.
Exclude test code and context teardown from the redundant-ensure_free
CodeQL query: a deliberate `ensure_free(ctx, N); ...; context_destroy(ctx)`
in a test (forcing a GC before teardown) is not a smell.
Run the test-bitstring native test in CI (main, macOS and FreeBSD
workflows, with valgrind where available).
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Continuation of:
These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later