From b0497bcae28d76d16c7c09d84fc971d302ab6bf2 Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Thu, 16 Apr 2026 10:29:24 -0400 Subject: [PATCH 1/9] Issue #3: Increase length fields in HToken and bits_env from uint8_t to size_t --- src/parsers/bits.c | 6 +++--- src/parsers/token.c | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/parsers/bits.c b/src/parsers/bits.c index 8fc6755..f050b7d 100644 --- a/src/parsers/bits.c +++ b/src/parsers/bits.c @@ -4,7 +4,7 @@ #include struct bits_env { - uint8_t length; + size_t length; uint8_t signedp; }; @@ -13,9 +13,9 @@ static HParseResult *parse_bits(void *env, HParseState *state) { HParsedToken *result = a_new(HParsedToken, 1); result->token_type = (env_->signedp ? TT_SINT : TT_UINT); if (env_->signedp) - result->sint = h_read_bits(&state->input_stream, env_->length, true); + result->sint = h_read_bits(&state->input_stream, (int)env_->length, true); else - result->uint = h_read_bits(&state->input_stream, env_->length, false); + result->uint = h_read_bits(&state->input_stream, (int)env_->length, false); result->index = 0; result->bit_length = 0; result->bit_offset = 0; diff --git a/src/parsers/token.c b/src/parsers/token.c index f67cf18..7baa824 100644 --- a/src/parsers/token.c +++ b/src/parsers/token.c @@ -5,12 +5,12 @@ typedef struct { uint8_t *str; - uint8_t len; + size_t len; } HToken; static HParseResult *parse_token(void *env, HParseState *state) { HToken *t = (HToken *)env; - for (int i = 0; i < t->len; ++i) { + for (size_t i = 0; i < t->len; ++i) { uint8_t chr = (uint8_t)h_read_bits(&state->input_stream, 8, false); if (t->str[i] != chr) { return NULL; @@ -76,11 +76,9 @@ HParser *h_token(const uint8_t *str, const size_t len) { return h_token__m(&system_allocator, str, len); } HParser *h_token__m(HAllocator *mm__, const uint8_t *str, const size_t len) { - // Length has to be <= 255 (uint8) as defined by HToken struct - assert(len <= UINT8_MAX); HToken *t = h_new(HToken, 1); uint8_t *str_cpy = h_new(uint8_t, len); memcpy(str_cpy, str, len); - t->str = str_cpy, t->len = (uint8_t)len; + t->str = str_cpy, t->len = len; return h_new_parser(mm__, &token_vt, t); } From 92bdb902cb2a7bc2b2b9e59e4a012b6d729640db Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Thu, 16 Apr 2026 10:36:41 -0400 Subject: [PATCH 2/9] Issue #6: Replace assert()-based input validation with explicit checks --- src/bitwriter.c | 15 ++++++++++----- src/datastructures.c | 6 ++++-- src/glue.c | 33 ++++++++++++++++++--------------- src/glue.h | 4 ++-- src/sloballoc.c | 6 ++++-- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/bitwriter.c b/src/bitwriter.c index c2b71bc..4588769 100644 --- a/src/bitwriter.c +++ b/src/bitwriter.c @@ -52,7 +52,10 @@ static void h_bit_writer_reserve(HBitWriter *w, size_t nbits) { } void h_bit_writer_put(HBitWriter *w, uint64_t data, size_t nbits) { - assert(nbits > 0); // Less than or equal to zero makes complete nonsense + if (nbits == 0) { + w->error = 1; + return; + } // expand size... h_bit_writer_reserve(w, nbits); @@ -90,10 +93,12 @@ void h_bit_writer_put(HBitWriter *w, uint64_t data, size_t nbits) { } const uint8_t *h_bit_writer_get_buffer(HBitWriter *w, size_t *len) { - assert(len != NULL); - assert(w != NULL); - // Not entirely sure how to handle a non-integral number of bytes... make it an error for now - assert(w->bit_offset == 0); // BUG: change this to some sane behaviour + if (w == NULL || len == NULL) + return NULL; + if (w->bit_offset != 0) { + w->error = 1; + return NULL; + } *len = w->index; return w->buf; diff --git a/src/datastructures.c b/src/datastructures.c index 46e10df..95d8ab4 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -112,7 +112,8 @@ void h_slist_push(HSlist *slist, void *item) { } bool h_slist_find(HSlist *slist, const void *item) { - assert(item != NULL); + if (item == NULL) + return false; HSlistNode *head = slist->head; while (head != NULL) { if (head->elem == item) @@ -123,7 +124,8 @@ bool h_slist_find(HSlist *slist, const void *item) { } HSlist *h_slist_remove_all(HSlist *slist, const void *item) { - assert(item != NULL); + if (item == NULL) + return slist; HSlistNode *node = slist->head; HSlistNode *prev = NULL; while (node != NULL) { diff --git a/src/glue.c b/src/glue.c index 87041e9..e965ba9 100644 --- a/src/glue.c +++ b/src/glue.c @@ -78,7 +78,8 @@ HParsedToken *h_make_(HArena *arena, HTokenType type) { } HParsedToken *h_make(HArena *arena, HTokenType type, void *value) { - assert(type >= TT_USER); + if (type < TT_USER) + return NULL; HParsedToken *ret = h_make_(arena, type); ret->user = value; return ret; @@ -129,25 +130,26 @@ HParsedToken *h_make_float(HArena *arena, float val) { // XXX -> internal HParsedToken *h_carray_index(const HCountedArray *a, size_t i) { - assert(i < a->used); + if (i >= a->used) + return NULL; return a->elements[i]; } size_t h_seq_len(const HParsedToken *p) { - assert(p != NULL); - assert(p->token_type == TT_SEQUENCE); + if (p == NULL || p->token_type != TT_SEQUENCE) + return 0; return p->seq->used; } HParsedToken **h_seq_elements(const HParsedToken *p) { - assert(p != NULL); - assert(p->token_type == TT_SEQUENCE); + if (p == NULL || p->token_type != TT_SEQUENCE) + return NULL; return p->seq->elements; } HParsedToken *h_seq_index(const HParsedToken *p, size_t i) { - assert(p != NULL); - assert(p->token_type == TT_SEQUENCE); + if (p == NULL || p->token_type != TT_SEQUENCE) + return NULL; return h_carray_index(p->seq, i); } @@ -172,17 +174,17 @@ HParsedToken *h_seq_index_vpath(const HParsedToken *p, size_t i, va_list va) { } void h_seq_snoc(HParsedToken *xs, const HParsedToken *x) { - assert(xs != NULL); - assert(xs->token_type == TT_SEQUENCE); + if (xs == NULL || xs->token_type != TT_SEQUENCE) + return; h_carray_append(xs->seq, (HParsedToken *)x); } void h_seq_append(HParsedToken *xs, const HParsedToken *ys) { - assert(xs != NULL); - assert(xs->token_type == TT_SEQUENCE); - assert(ys != NULL); - assert(ys->token_type == TT_SEQUENCE); + if (xs == NULL || xs->token_type != TT_SEQUENCE) + return; + if (ys == NULL || ys->token_type != TT_SEQUENCE) + return; for (size_t i = 0; i < ys->seq->used; i++) h_carray_append(xs->seq, ys->seq->elements[i]); @@ -191,7 +193,8 @@ void h_seq_append(HParsedToken *xs, const HParsedToken *ys) { // Flatten nested sequences. Always returns a sequence. // If input element is not a sequence, returns it as a singleton sequence. const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p) { - assert(p != NULL); + if (p == NULL) + return NULL; HParsedToken *ret = h_make_seq(arena); switch (p->token_type) { diff --git a/src/glue.h b/src/glue.h index 4ae2cca..b6175ec 100644 --- a/src/glue.h +++ b/src/glue.h @@ -218,8 +218,8 @@ HParsedToken *h_make_float(HArena *arena, float val); /** Extract (cast) type-specific value back from HParsedTokens... */ -/** Pass-through assertion that a given token has the expected type. */ -#define h_assert_type(T, P) (assert(P->token_type == (HTokenType)T), P) +/** Pass-through check that a given token has the expected type. Returns NULL on mismatch. */ +#define h_assert_type(T, P) ((P)->token_type == (HTokenType)(T) ? (P) : NULL) /** Convenience short-hand forms of h_assert_type. */ #define H_ASSERT(TYP, TOK) h_assert_type(TT_##TYP, TOK) diff --git a/src/sloballoc.c b/src/sloballoc.c index 7643a3e..6b2f656 100644 --- a/src/sloballoc.c +++ b/src/sloballoc.c @@ -25,8 +25,10 @@ struct slob { SLOB *slobinit(void *mem, size_t size) { SLOB *slob = mem; - assert(size >= sizeof(SLOB) + sizeof(struct block)); - assert(size < UINTPTR_MAX - (uintptr_t)mem); + if (size < sizeof(SLOB) + sizeof(struct block)) + return NULL; + if (size >= UINTPTR_MAX - (uintptr_t)mem) + return NULL; slob = mem; slob->size = size - sizeof(SLOB); From 5021000ab168b8f6ae8d460f0b9372686d4023e7 Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Thu, 16 Apr 2026 10:49:20 -0400 Subject: [PATCH 3/9] Fix token length test case --- tests/parsers/test_token.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/parsers/test_token.c b/tests/parsers/test_token.c index 611191e..493a03b 100644 --- a/tests/parsers/test_token.c +++ b/tests/parsers/test_token.c @@ -38,23 +38,25 @@ static void test_reshape_token(gconstpointer backend) { } } -// Test token.c: len not > UINT8_MAX assert +// Test token.c: tokens longer than 255 bytes are now supported static void test_token_len_assert(gconstpointer backend) { - (void)backend; + HParserBackend be = (HParserBackend)GPOINTER_TO_INT(backend); - if (g_test_subprocess()) { - uint8_t expected[256]; - memset(expected, 0x41, sizeof(expected)); + uint8_t expected[256]; + memset(expected, 0x41, sizeof(expected)); - HParser *parser = h_token(expected, sizeof(expected)); + HParser *parser = h_token(expected, sizeof(expected)); + g_check_cmp_ptr(parser, !=, NULL); - // Shouldn't get here - (void)parser; - return; + h_compile(parser, be, NULL); + HParseResult *res = h_parse(parser, expected, sizeof(expected)); + g_check_cmp_ptr(res, !=, NULL); + if (res) { + g_check_cmp_ptr(res->ast, !=, NULL); + if (res->ast && res->ast->token_type == TT_BYTES) + g_check_cmp_int(res->ast->bytes.len, ==, 256); + h_parse_result_free(res); } - - g_test_trap_subprocess(NULL, 0, 0); - g_test_trap_assert_failed(); } void register_token_tests(void) { From 68a46967ac36bd0f631042745f854b5f27fde72a Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Thu, 16 Apr 2026 11:37:01 -0400 Subject: [PATCH 4/9] Add ruff linting as a pipeline step --- .github/workflows/pipeline.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 1b926ab..48edb9b 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -22,6 +22,18 @@ jobs: run: | find src examples -name '*.c' -o -name '*.h' | xargs clang-format --dry-run --Werror + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install ruff + run: pip install ruff + + - name: Lint Python and SCons files + run: | + ruff check $(find . -path ./build -prune -o \( -name "*.py" -o -name "SConstruct" -o -name "SConscript" \) -print) + scons-test: runs-on: ubuntu-latest steps: @@ -40,7 +52,7 @@ jobs: build-deb: runs-on: ubuntu-latest - needs: [clang-format, scons-test] + needs: [clang-format, ruff, scons-test] steps: - uses: actions/checkout@v4 From ab4c9c697cf79ab1a431aed5582ada0bc763e7d0 Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Thu, 16 Apr 2026 11:37:10 -0400 Subject: [PATCH 5/9] Update version and changelog --- VERSION | 2 +- debian/changelog | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 45a1b3f..38f77a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.2 +2.0.1 diff --git a/debian/changelog b/debian/changelog index 3529a5a..46562f1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +libmicrohammer (2.0.1-1) unstable; urgency=medium + + * Widen HToken.len and bits_env.length from uint8_t to size_t, fixing silent + integer truncation for tokens and bit counts exceeding 255 (closes #3) + * Replace assert()-based input validation with explicit guards in bitwriter.c, + glue.c, glue.h, datastructures.c, and sloballoc.c so checks survive -DNDEBUG + (closes #6) + * Update h_assert_type macro to return NULL on type mismatch unconditionally + * Update token length test to verify 256-byte tokens parse correctly + * Add ruff linting of Python and SCons files to CI pipeline + + -- Mahmoud Elbasiouny Thu, 16 Apr 2026 12:00:00 -0400 + libmicrohammer (2.0.0-1) unstable; urgency=medium * Reintroduce Python, Java/JNI, and C++ language bindings From 3956958b75c6bf8b24c80a2e2f83831396af7689 Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Fri, 17 Apr 2026 11:33:32 -0400 Subject: [PATCH 6/9] Address PR review feedback on input validation approach, introducing HAMMER_ASSERT macro --- src/bitwriter.c | 10 ++++------ src/datastructures.c | 6 ++---- src/glue.c | 33 +++++++++++++++------------------ src/glue.h | 7 +++---- src/internal.h | 6 ++++++ src/parsers/bits.c | 1 + tests/parsers/test_token.c | 9 +++++---- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/bitwriter.c b/src/bitwriter.c index 4588769..639cfcd 100644 --- a/src/bitwriter.c +++ b/src/bitwriter.c @@ -52,10 +52,7 @@ static void h_bit_writer_reserve(HBitWriter *w, size_t nbits) { } void h_bit_writer_put(HBitWriter *w, uint64_t data, size_t nbits) { - if (nbits == 0) { - w->error = 1; - return; - } + HAMMER_ASSERT(nbits > 0); // expand size... h_bit_writer_reserve(w, nbits); @@ -93,8 +90,9 @@ void h_bit_writer_put(HBitWriter *w, uint64_t data, size_t nbits) { } const uint8_t *h_bit_writer_get_buffer(HBitWriter *w, size_t *len) { - if (w == NULL || len == NULL) - return NULL; + HAMMER_ASSERT(w != NULL); + HAMMER_ASSERT(len != NULL); + // Non-byte-boundary writes are unsupported; partial final bytes are not returned. if (w->bit_offset != 0) { w->error = 1; return NULL; diff --git a/src/datastructures.c b/src/datastructures.c index 95d8ab4..587b264 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -112,8 +112,7 @@ void h_slist_push(HSlist *slist, void *item) { } bool h_slist_find(HSlist *slist, const void *item) { - if (item == NULL) - return false; + HAMMER_ASSERT(item != NULL); HSlistNode *head = slist->head; while (head != NULL) { if (head->elem == item) @@ -124,8 +123,7 @@ bool h_slist_find(HSlist *slist, const void *item) { } HSlist *h_slist_remove_all(HSlist *slist, const void *item) { - if (item == NULL) - return slist; + HAMMER_ASSERT(item != NULL); HSlistNode *node = slist->head; HSlistNode *prev = NULL; while (node != NULL) { diff --git a/src/glue.c b/src/glue.c index e965ba9..b74491d 100644 --- a/src/glue.c +++ b/src/glue.c @@ -78,8 +78,7 @@ HParsedToken *h_make_(HArena *arena, HTokenType type) { } HParsedToken *h_make(HArena *arena, HTokenType type, void *value) { - if (type < TT_USER) - return NULL; + HAMMER_ASSERT(type >= TT_USER); HParsedToken *ret = h_make_(arena, type); ret->user = value; return ret; @@ -130,26 +129,25 @@ HParsedToken *h_make_float(HArena *arena, float val) { // XXX -> internal HParsedToken *h_carray_index(const HCountedArray *a, size_t i) { - if (i >= a->used) - return NULL; + HAMMER_ASSERT(i < a->used); return a->elements[i]; } size_t h_seq_len(const HParsedToken *p) { - if (p == NULL || p->token_type != TT_SEQUENCE) - return 0; + HAMMER_ASSERT(p != NULL); + HAMMER_ASSERT(p->token_type == TT_SEQUENCE); return p->seq->used; } HParsedToken **h_seq_elements(const HParsedToken *p) { - if (p == NULL || p->token_type != TT_SEQUENCE) - return NULL; + HAMMER_ASSERT(p != NULL); + HAMMER_ASSERT(p->token_type == TT_SEQUENCE); return p->seq->elements; } HParsedToken *h_seq_index(const HParsedToken *p, size_t i) { - if (p == NULL || p->token_type != TT_SEQUENCE) - return NULL; + HAMMER_ASSERT(p != NULL); + HAMMER_ASSERT(p->token_type == TT_SEQUENCE); return h_carray_index(p->seq, i); } @@ -174,17 +172,17 @@ HParsedToken *h_seq_index_vpath(const HParsedToken *p, size_t i, va_list va) { } void h_seq_snoc(HParsedToken *xs, const HParsedToken *x) { - if (xs == NULL || xs->token_type != TT_SEQUENCE) - return; + HAMMER_ASSERT(xs != NULL); + HAMMER_ASSERT(xs->token_type == TT_SEQUENCE); h_carray_append(xs->seq, (HParsedToken *)x); } void h_seq_append(HParsedToken *xs, const HParsedToken *ys) { - if (xs == NULL || xs->token_type != TT_SEQUENCE) - return; - if (ys == NULL || ys->token_type != TT_SEQUENCE) - return; + HAMMER_ASSERT(xs != NULL); + HAMMER_ASSERT(xs->token_type == TT_SEQUENCE); + HAMMER_ASSERT(ys != NULL); + HAMMER_ASSERT(ys->token_type == TT_SEQUENCE); for (size_t i = 0; i < ys->seq->used; i++) h_carray_append(xs->seq, ys->seq->elements[i]); @@ -193,8 +191,7 @@ void h_seq_append(HParsedToken *xs, const HParsedToken *ys) { // Flatten nested sequences. Always returns a sequence. // If input element is not a sequence, returns it as a singleton sequence. const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p) { - if (p == NULL) - return NULL; + HAMMER_ASSERT(p != NULL); HParsedToken *ret = h_make_seq(arena); switch (p->token_type) { diff --git a/src/glue.h b/src/glue.h index b6175ec..c2e2a3f 100644 --- a/src/glue.h +++ b/src/glue.h @@ -26,8 +26,7 @@ #define HAMMER_GLUE__H #include "hammer.h" - -#include +#include "internal.h" /** * Grammar specification @@ -218,8 +217,8 @@ HParsedToken *h_make_float(HArena *arena, float val); /** Extract (cast) type-specific value back from HParsedTokens... */ -/** Pass-through check that a given token has the expected type. Returns NULL on mismatch. */ -#define h_assert_type(T, P) ((P)->token_type == (HTokenType)(T) ? (P) : NULL) +/** Pass-through assertion that a given token has the expected type. Aborts on mismatch. */ +#define h_assert_type(T, P) (HAMMER_ASSERT((P)->token_type == (HTokenType)(T)), (P)) /** Convenience short-hand forms of h_assert_type. */ #define H_ASSERT(TYP, TOK) h_assert_type(TT_##TYP, TOK) diff --git a/src/internal.h b/src/internal.h index 3afc416..9e7ba46 100644 --- a/src/internal.h +++ b/src/internal.h @@ -28,6 +28,7 @@ #include #include +#include #include /* "Internal" in this case means "we're not ready to commit @@ -47,6 +48,11 @@ } while (0) #endif +/* Unconditional assertion for programmer errors — fires in all builds, including -DNDEBUG. */ +#define HAMMER_ASSERT(cond) \ + ((void)((cond) || (fprintf(stderr, "Hammer assertion failed: %s (%s:%d)\n", \ + #cond, __FILE__, __LINE__), abort(), 0))) + #define HAMMER_FN_IMPL_NOARGS(rtype_t, name) \ rtype_t name(void) { return name##__m(system_allocator); } \ rtype_t name##__m(HAllocator *mm__) diff --git a/src/parsers/bits.c b/src/parsers/bits.c index f050b7d..42bcf80 100644 --- a/src/parsers/bits.c +++ b/src/parsers/bits.c @@ -12,6 +12,7 @@ static HParseResult *parse_bits(void *env, HParseState *state) { struct bits_env *env_ = env; HParsedToken *result = a_new(HParsedToken, 1); result->token_type = (env_->signedp ? TT_SINT : TT_UINT); + // h_read_bits takes int; cast is required by its signature if (env_->signedp) result->sint = h_read_bits(&state->input_stream, (int)env_->length, true); else diff --git a/tests/parsers/test_token.c b/tests/parsers/test_token.c index 493a03b..625266a 100644 --- a/tests/parsers/test_token.c +++ b/tests/parsers/test_token.c @@ -39,22 +39,23 @@ static void test_reshape_token(gconstpointer backend) { } // Test token.c: tokens longer than 255 bytes are now supported +#define TOKEN_TEST_LEN 256 static void test_token_len_assert(gconstpointer backend) { HParserBackend be = (HParserBackend)GPOINTER_TO_INT(backend); - uint8_t expected[256]; + uint8_t expected[TOKEN_TEST_LEN]; memset(expected, 0x41, sizeof(expected)); - HParser *parser = h_token(expected, sizeof(expected)); + HParser *parser = h_token(expected, TOKEN_TEST_LEN); g_check_cmp_ptr(parser, !=, NULL); h_compile(parser, be, NULL); - HParseResult *res = h_parse(parser, expected, sizeof(expected)); + HParseResult *res = h_parse(parser, expected, TOKEN_TEST_LEN); g_check_cmp_ptr(res, !=, NULL); if (res) { g_check_cmp_ptr(res->ast, !=, NULL); if (res->ast && res->ast->token_type == TT_BYTES) - g_check_cmp_int(res->ast->bytes.len, ==, 256); + g_check_cmp_int(res->ast->bytes.len, ==, TOKEN_TEST_LEN); h_parse_result_free(res); } } From 5eb17859ffac4572d3925c841447c8cf6b88b48d Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Fri, 17 Apr 2026 11:40:25 -0400 Subject: [PATCH 7/9] Update changelog to include HAMMER_ASSERT --- debian/changelog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/debian/changelog b/debian/changelog index 46562f1..7a814d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,14 +2,14 @@ libmicrohammer (2.0.1-1) unstable; urgency=medium * Widen HToken.len and bits_env.length from uint8_t to size_t, fixing silent integer truncation for tokens and bit counts exceeding 255 (closes #3) - * Replace assert()-based input validation with explicit guards in bitwriter.c, - glue.c, glue.h, datastructures.c, and sloballoc.c so checks survive -DNDEBUG - (closes #6) - * Update h_assert_type macro to return NULL on type mismatch unconditionally + * Introduce HAMMER_ASSERT in internal.h: unconditional abort for programmer + errors that survives -DNDEBUG; replaces assert()-based guards in bitwriter.c, + glue.c, glue.h, and datastructures.c (closes #6) + * Update h_assert_type macro to abort on type mismatch via HAMMER_ASSERT * Update token length test to verify 256-byte tokens parse correctly * Add ruff linting of Python and SCons files to CI pipeline - -- Mahmoud Elbasiouny Thu, 16 Apr 2026 12:00:00 -0400 + -- Mahmoud Elbasiouny Fri, 17 Apr 2026 12:00:00 -0400 libmicrohammer (2.0.0-1) unstable; urgency=medium From 6b069c754343da5aec12859e9a1806911c55f9f7 Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Fri, 17 Apr 2026 11:45:56 -0400 Subject: [PATCH 8/9] Address linting issues: clang-format HAMMER_ASSERT macro --- src/internal.h | 7 ++++--- tests/parsers/test_token.c | 2 +- tests/t_bitreader.c | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/internal.h b/src/internal.h index 9e7ba46..e1b7791 100644 --- a/src/internal.h +++ b/src/internal.h @@ -49,9 +49,10 @@ #endif /* Unconditional assertion for programmer errors — fires in all builds, including -DNDEBUG. */ -#define HAMMER_ASSERT(cond) \ - ((void)((cond) || (fprintf(stderr, "Hammer assertion failed: %s (%s:%d)\n", \ - #cond, __FILE__, __LINE__), abort(), 0))) +#define HAMMER_ASSERT(cond) \ + ((void)((cond) || \ + (fprintf(stderr, "Hammer assertion failed: %s (%s:%d)\n", #cond, __FILE__, __LINE__), \ + abort(), 0))) #define HAMMER_FN_IMPL_NOARGS(rtype_t, name) \ rtype_t name(void) { return name##__m(system_allocator); } \ diff --git a/tests/parsers/test_token.c b/tests/parsers/test_token.c index 625266a..26f0b88 100644 --- a/tests/parsers/test_token.c +++ b/tests/parsers/test_token.c @@ -63,7 +63,7 @@ static void test_token_len_assert(gconstpointer backend) { void register_token_tests(void) { g_test_add_data_func("/core/parser/packrat/reshape_token", GINT_TO_POINTER(PB_PACKRAT), test_reshape_token); - + g_test_add_data_func("/core/parser/packrat/token_len_assert", GINT_TO_POINTER(PB_PACKRAT), test_token_len_assert); } diff --git a/tests/t_bitreader.c b/tests/t_bitreader.c index c7cdf93..9911b23 100644 --- a/tests/t_bitreader.c +++ b/tests/t_bitreader.c @@ -234,4 +234,3 @@ void register_bitreader_tests(void) { g_test_add_func("/core/bitreader/byte_le_fast_path", test_read_bits_byte_le_fast_path); g_test_add_func("/core/bitreader/byte_le_slow_path", test_read_bits_byte_le_slow_path); } - From d40c3bb720d446794775bf5e25172b9fda48909e Mon Sep 17 00:00:00 2001 From: "Elbasiouny, Mahmoud" Date: Fri, 17 Apr 2026 14:01:10 -0400 Subject: [PATCH 9/9] Replace bit_offset error return with HAMMER_ASSERT in h_bit_writer_get_buffer --- src/bitwriter.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bitwriter.c b/src/bitwriter.c index 639cfcd..84a3761 100644 --- a/src/bitwriter.c +++ b/src/bitwriter.c @@ -92,11 +92,7 @@ void h_bit_writer_put(HBitWriter *w, uint64_t data, size_t nbits) { const uint8_t *h_bit_writer_get_buffer(HBitWriter *w, size_t *len) { HAMMER_ASSERT(w != NULL); HAMMER_ASSERT(len != NULL); - // Non-byte-boundary writes are unsupported; partial final bytes are not returned. - if (w->bit_offset != 0) { - w->error = 1; - return NULL; - } + HAMMER_ASSERT(w->bit_offset == 0); *len = w->index; return w->buf;