From e7947dc9a410ff5ba268f379fbe195cbfddea932 Mon Sep 17 00:00:00 2001 From: Schaich Date: Wed, 9 Jun 2021 22:37:16 +0900 Subject: [PATCH] Merge String Constant The `CALCIUM` "name" is a macro which expands to a string constant. Referencing the macro twice will cause it to be expanded twice, resulting in two string instances which have identical content. By default, gcc will deduplicate these two strings into the same memory region as gcc detects the duplicated constant, even when optimization turned off (see -fmerge-constants and -fmerge-all-constants GCC options). The C Language specification does not require duplicated constants to be deduplicated, and, in fact, the GCC manual page also explicitly states this optimization is not performed for all targets. Visual C++, in debug mode, does not deduplicate constants. This results in `count += strchr(CALCIUM,x) - CALCIUM` yielding to negative values as the substracted CALCIUM's expansion resides on a greater memory address then the memory allocated for the expansion passed to `strchr`. The value of `count` is used to compute the checksum, which then is not only faulty, but also used as an array index without previously checking whether or not the index is within the array bounds (modulo of a negative integer is negative, which means out of bounds). This will cause very difficult to predict behavior, in most cases, however, it will cause a segmentation fault. Manually allocate a memory range to contain the string, and use this range instead of expanding the macro multiple times. --- backend/medical.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/medical.c b/backend/medical.c index d110502e..bcd02fb2 100644 --- a/backend/medical.c +++ b/backend/medical.c @@ -236,8 +236,9 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len add_checksum = symbol->option_2 == 1; for (i = 0; i < length; i++) { + const char calcium[] = CALCIUM; if (add_checksum) { - count += strchr(CALCIUM, source[i]) - CALCIUM; + count += strchr(calcium, source[i]) - calcium; if (i + 1 == length) { checksum = count % 16; if (checksum) { @@ -249,7 +250,7 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len strcat(dest, CodaTable[checksum]); } } - lookup(CALCIUM, CodaTable, source[i], dest); + lookup(calcium, CodaTable, source[i], dest); } expand(symbol, dest);