From 7bb58f2d546957dc4fe9a85fe06a1917f39c2c98 Mon Sep 17 00:00:00 2001 From: Mateusz Front Date: Thu, 13 Nov 2025 15:17:41 +0100 Subject: [PATCH] Support creating and matching bitstrings that are in fact binaries (size divisible by 8) Signed-off-by: Mateusz Front --- src/libAtomVM/opcodesswitch.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index d1fdeacb4..416f62dae 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -5447,20 +5447,21 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) term bs_bin = term_get_match_state_binary(src); avm_int_t bs_offset = term_get_match_state_offset(src); - if (unit != 8) { - TRACE("bs_get_binary2: Unsupported: unit must be 8.\n"); - RAISE_ERROR(UNSUPPORTED_ATOM); - } avm_int_t size_val = 0; if (term_is_integer(size)) { - size_val = term_to_int(size); + size_val = term_to_int(size) * unit; + if (size_val % 8) { + TRACE("bs_get_binary2: Unsupported: size must be divisible by 8, got: %ld\n", size_val); + RAISE_ERROR(UNSUPPORTED_ATOM); + } + size_val = size_val / 8; } else if (size == ALL_ATOM) { size_val = term_binary_size(bs_bin) - bs_offset / 8; } else { TRACE("bs_get_binary2: size is neither an integer nor the atom `all`\n"); RAISE_ERROR(BADARG_ATOM); } - if (bs_offset % unit != 0) { + if (bs_offset % 8 != 0) { TRACE("bs_get_binary2: Unsupported. Offset on binary read must be aligned on byte boundaries.\n"); RAISE_ERROR(BADARG_ATOM); } @@ -5471,11 +5472,11 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("bs_get_binary2/7, fail=%u src=%p live=%u unit=%u\n", (unsigned) fail, (void *) bs_bin, (unsigned) live, (unsigned) unit); - if ((unsigned int) (bs_offset / unit + size_val) > term_binary_size(bs_bin)) { + if ((unsigned int) (bs_offset / 8 + size_val) > term_binary_size(bs_bin)) { TRACE("bs_get_binary2: insufficient capacity -- bs_offset = %d, size_val = %d\n", (int) bs_offset, (int) size_val); JUMP_TO_ADDRESS(mod->labels[fail]); } else { - term_set_match_state_offset(src, bs_offset + size_val * unit); + term_set_match_state_offset(src, bs_offset + size_val * 8); TRIM_LIVE_REGS(live); // there is always room for a MAX_REG + 1 register, used as working register @@ -6940,7 +6941,12 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } } else { VERIFY_IS_INTEGER(size, "bs_create_bin/6", fail); - avm_int_t signed_size_value = term_to_int(size); + avm_int_t signed_size_value = term_to_int(size) * segment_unit; + if (UNLIKELY(signed_size_value % 8)) { + TRACE("bs_create_bin/6: Unsupported: size must be dvisible by 8, got: %ld\n", signed_size_value); + RAISE_ERROR(UNSUPPORTED_ATOM); + } + signed_size_value = signed_size_value / 8; if (UNLIKELY(signed_size_value < 0)) { if (fail == 0) { RAISE_ERROR(BADARG_ATOM); @@ -6957,6 +6963,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } } segment_size = signed_size_value; + segment_unit = 8; } break; } @@ -7109,7 +7116,12 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("bs_create_bin/6: size value less than 0: %i\n", (int) signed_size_value); RAISE_ERROR(BADARG_ATOM); } - size_value = (size_t) signed_size_value; + size_value = (size_t) signed_size_value * segment_unit; + if (UNLIKELY(size_value % 8)) { + TRACE("bs_create_bin/6: Unsupported: bitstring size (%d) is not evenly divisible by 8\n", (int) size_value); + RAISE_ERROR(UNSUPPORTED_ATOM); + } + size_value = size_value / 8; if (size_value > src_size) { if (fail == 0) { RAISE_ERROR(BADARG_ATOM);