From e55e9c9fdeb2da759622a0fd604945b2c9e5a483 Mon Sep 17 00:00:00 2001 From: Sophie Winter Date: Sun, 20 Jul 2025 02:03:54 -0700 Subject: [PATCH 1/3] Fix alignment issue in md_mark_store_ptr() --- src/md4c.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/md4c.c b/src/md4c.c index e3f5cf9d..ec526dcd 100644 --- a/src/md4c.c +++ b/src/md4c.c @@ -147,7 +147,7 @@ #define SZ_MAX (sizeof(SZ) == 8 ? UINT64_MAX : UINT32_MAX) #define OFF_MAX (sizeof(OFF) == 8 ? UINT64_MAX : UINT32_MAX) -typedef struct MD_MARK_tag MD_MARK; +typedef union MD_MARK_tag MD_MARK; typedef struct MD_BLOCK_tag MD_BLOCK; typedef struct MD_CONTAINER_tag MD_CONTAINER; typedef struct MD_REF_DEF_tag MD_REF_DEF; @@ -2519,20 +2519,23 @@ md_free_ref_defs(MD_CTX* ctx) * (Keep this struct as small as possible to fit as much of them into CPU * cache line.) */ -struct MD_MARK_tag { - OFF beg; - OFF end; +union MD_MARK_tag { + struct { + OFF beg; + OFF end; - /* For unresolved openers, 'next' may be used to form a stack of - * unresolved open openers. - * - * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the - * respective closer/opener. - */ - int prev; - int next; - CHAR ch; - unsigned char flags; + /* For unresolved openers, 'next' may be used to form a stack of + * unresolved open openers. + * + * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the + * respective closer/opener. + */ + int prev; + int next; + CHAR ch; + unsigned char flags; + }; + void* pointer; // Dummy marks can sometimes store a pointer }; /* Mark flags (these apply to ALL mark types). */ @@ -2653,8 +2656,7 @@ md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) return top; } -/* Sometimes, we need to store a pointer into the mark. It is quite rare - * so we do not bother to make MD_MARK use union, and it can only happen +/* Sometimes, we need to store a pointer into the mark. It can only happen * for dummy marks. */ static inline void md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) @@ -2664,7 +2666,7 @@ md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) /* Check only members beg and end are misused for this. */ MD_ASSERT(sizeof(void*) <= 2 * sizeof(OFF)); - memcpy(mark, &ptr, sizeof(void*)); + memcpy(&mark->pointer, &ptr, sizeof(void*)); } static inline void* From 549cefe2ba679065067d3021b13d07b26c7b2d76 Mon Sep 17 00:00:00 2001 From: Sophie Winter Date: Sun, 20 Jul 2025 21:38:31 -0700 Subject: [PATCH 2/3] Change union portion of MD_MARK_tag to just beg and end --- src/md4c.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/md4c.c b/src/md4c.c index ec526dcd..2c9e8777 100644 --- a/src/md4c.c +++ b/src/md4c.c @@ -147,7 +147,7 @@ #define SZ_MAX (sizeof(SZ) == 8 ? UINT64_MAX : UINT32_MAX) #define OFF_MAX (sizeof(OFF) == 8 ? UINT64_MAX : UINT32_MAX) -typedef union MD_MARK_tag MD_MARK; +typedef struct MD_MARK_tag MD_MARK; typedef struct MD_BLOCK_tag MD_BLOCK; typedef struct MD_CONTAINER_tag MD_CONTAINER; typedef struct MD_REF_DEF_tag MD_REF_DEF; @@ -2519,23 +2519,25 @@ md_free_ref_defs(MD_CTX* ctx) * (Keep this struct as small as possible to fit as much of them into CPU * cache line.) */ -union MD_MARK_tag { - struct { - OFF beg; - OFF end; - - /* For unresolved openers, 'next' may be used to form a stack of - * unresolved open openers. - * - * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the - * respective closer/opener. - */ - int prev; - int next; - CHAR ch; - unsigned char flags; +struct MD_MARK_tag { + union { + struct { + OFF beg; + OFF end; + }; + void* pointer; // Dummy marks can sometimes store a pointer }; - void* pointer; // Dummy marks can sometimes store a pointer + + /* For unresolved openers, 'next' may be used to form a stack of + * unresolved open openers. + * + * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the + * respective closer/opener. + */ + int prev; + int next; + CHAR ch; + unsigned char flags; }; /* Mark flags (these apply to ALL mark types). */ @@ -2663,9 +2665,6 @@ md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) { MD_MARK* mark = &ctx->marks[mark_index]; MD_ASSERT(mark->ch == 'D'); - - /* Check only members beg and end are misused for this. */ - MD_ASSERT(sizeof(void*) <= 2 * sizeof(OFF)); memcpy(&mark->pointer, &ptr, sizeof(void*)); } From 664a772d58e9df5993de82aca352ca77c1ee4d03 Mon Sep 17 00:00:00 2001 From: Sophie Winter Date: Sun, 20 Jul 2025 22:01:46 -0700 Subject: [PATCH 3/3] Simplify mark pointers more --- src/md4c.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/md4c.c b/src/md4c.c index 2c9e8777..0e86f2a0 100644 --- a/src/md4c.c +++ b/src/md4c.c @@ -2663,19 +2663,15 @@ md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) static inline void md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) { - MD_MARK* mark = &ctx->marks[mark_index]; - MD_ASSERT(mark->ch == 'D'); - memcpy(&mark->pointer, &ptr, sizeof(void*)); + MD_ASSERT(ctx->marks[mark_index].ch == 'D'); + ctx->marks[mark_index].pointer = ptr; } static inline void* md_mark_get_ptr(MD_CTX* ctx, int mark_index) { - void* ptr; - MD_MARK* mark = &ctx->marks[mark_index]; - MD_ASSERT(mark->ch == 'D'); - memcpy(&ptr, mark, sizeof(void*)); - return ptr; + MD_ASSERT(ctx->marks[mark_index].ch == 'D'); + return ctx->marks[mark_index].pointer; } static inline void