diff --git a/src/pcre2_intmodedep.h b/src/pcre2_intmodedep.h index 355938e..7172acf 100644 --- a/src/pcre2_intmodedep.h +++ b/src/pcre2_intmodedep.h @@ -584,14 +584,21 @@ typedef struct pcre2_real_match_context { uint32_t recursion_limit; } pcre2_real_match_context; -/* The real compiled code structure */ +/* The real compiled code structure. The type for the blocksize field is +defined specially because it is required in pcre2_serialize_decode() when +copying the size from possibly unaligned memory into a variable of the same +type. Use a macro rather than a typedef to avoid compiler warnings when this +file is included multiple times by pcre2test. */ + +#undef CODE_BLOCKSIZE_TYPE +#define CODE_BLOCKSIZE_TYPE size_t typedef struct pcre2_real_code { pcre2_memctl memctl; /* Memory control fields */ const uint8_t *tables; /* The character tables */ void *executable_jit; /* Pointer to JIT code */ uint8_t start_bitmap[32]; /* Bitmap for starting code unit < 256 */ - size_t blocksize; /* Total (bytes) that was malloc-ed */ + CODE_BLOCKSIZE_TYPE blocksize; /* Total (bytes) that was malloc-ed */ uint32_t magic_number; /* Paranoid and endianness check */ uint32_t compile_options; /* Options passed to pcre2_compile() */ uint32_t overall_options; /* Options after processing the pattern */ diff --git a/src/pcre2_serialize.c b/src/pcre2_serialize.c index 2eb3853..01ae579 100644 --- a/src/pcre2_serialize.c +++ b/src/pcre2_serialize.c @@ -150,7 +150,6 @@ const pcre2_memctl *memctl = (gcontext != NULL) ? &gcontext->memctl : &PRIV(default_compile_context).memctl; const uint8_t *src_bytes; -pcre2_real_code *src_re; pcre2_real_code *dst_re; uint8_t *tables; int32_t i, j; @@ -178,15 +177,22 @@ memcpy(tables, src_bytes, tables_length); *(PCRE2_SIZE *)(tables + tables_length) = number_of_codes; src_bytes += tables_length; -/* Decode byte stream. */ +/* Decode the byte stream. We must not try to read the size from the compiled +code block in the stream, because it might be unaligned, which causes errors on +hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type +of the blocksize field is given its own name to ensure that it is the same here +as in the block. */ for (i = 0; i < number_of_codes; i++) { - src_re = (pcre2_real_code *)src_bytes; + CODE_BLOCKSIZE_TYPE blocksize; + memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize), + sizeof(CODE_BLOCKSIZE_TYPE)); /* The allocator provided by gcontext replaces the original one. */ - dst_re = (pcre2_real_code *)PRIV(memctl_malloc) - (src_re->blocksize, (pcre2_memctl *)gcontext); + + dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize, + (pcre2_memctl *)gcontext); if (dst_re == NULL) { memctl->free(tables, memctl->memory_data); @@ -199,17 +205,18 @@ for (i = 0; i < number_of_codes; i++) } /* The new allocator must be preserved. */ + memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl), - src_bytes + sizeof(pcre2_memctl), - src_re->blocksize - sizeof(pcre2_memctl)); + src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl)); /* At the moment only one table is supported. */ + dst_re->tables = tables; dst_re->executable_jit = NULL; dst_re->flags |= PCRE2_DEREF_TABLES; codes[i] = dst_re; - src_bytes += src_re->blocksize; + src_bytes += blocksize; } return number_of_codes;