From edaa2120714dc2eac24f20f3b78a38082d98febc Mon Sep 17 00:00:00 2001 From: gitlost Date: Fri, 2 Oct 2026 22:17:04 +0100 Subject: [PATCH] composite: validate `warn_level` using new `WARN_LEVEL_MASK` mask, silently resetting to `WARN_DEFAULT` if not valid (ticket #359, props Andre Maute) --- backend/composite.c | 2 +- backend/library.c | 8 ++++++-- backend/tests/test_composite.c | 37 +++++++++++++++++++--------------- backend/tests/test_library.c | 4 +++- backend/zint.h | 1 + 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/backend/composite.c b/backend/composite.c index c98dfcbb..05a34b62 100644 --- a/backend/composite.c +++ b/backend/composite.c @@ -946,7 +946,7 @@ INTERNAL int zint_composite(struct zint_symbol *symbol, unsigned char source[], /* Hack to initialize `warn_number` to warning (if any) returned by `zint_gs1_verify()` */ warn_number = symbol->warn_level >> 8; - symbol->warn_level &= 0xFF; + symbol->warn_level &= WARN_LEVEL_MASK; assert(warn_number < ZINT_ERROR); /* Perform sanity checks on input options first */ diff --git a/backend/library.c b/backend/library.c index 9ec0c305..aa19ab8f 100644 --- a/backend/library.c +++ b/backend/library.c @@ -247,7 +247,7 @@ INTERNAL int zint_plot_vector(struct zint_symbol *symbol, int rotate_angle, int /* Helper to convert `error_number` based on `warn_level` */ static int error_warn_level(int error_number, struct zint_symbol *symbol) { - if (error_number < ZINT_ERROR && (symbol->warn_level & 0xFF) == WARN_FAIL_ALL) { + if (error_number < ZINT_ERROR && (symbol->warn_level & WARN_LEVEL_MASK) == WARN_FAIL_ALL) { /* Convert to error equivalent */ if (error_number == ZINT_WARN_NONCOMPLIANT) { error_number = ZINT_ERROR_NONCOMPLIANT; @@ -1152,6 +1152,9 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[ if (symbol->border_width < 0 || symbol->border_width > 100) { return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 768, "Border width out of range (0 to 100)"); } + if ((symbol->warn_level & WARN_LEVEL_MASK) != WARN_LEVEL_MASK) { + symbol->warn_level = WARN_DEFAULT; /* Silently reset */ + } if (symbol->rows >= 200) { /* Check for stacking too many symbols */ return error_tag(ZINT_ERROR_TOO_LONG, symbol, 770, "Too many stacked symbols (maximum 200)"); @@ -1248,7 +1251,8 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[ return error_tag(error_number, symbol, -1, NULL); } warn_number = error_number; /* Override any previous warning (errtxt has been overwritten) */ - symbol->warn_level |= (warn_number << 8); /* Hack to let `zint_composite()` know */ + /* Hack to let `zint_composite()` know */ + symbol->warn_level = (symbol->warn_level & WARN_LEVEL_MASK) | (warn_number << 8); } memcpy(local_segs[0].source, reduced, local_segs[0].length + 1); /* Include terminating NUL */ /* Set content segs for non-composites (composites set their own content segs) */ diff --git a/backend/tests/test_composite.c b/backend/tests/test_composite.c index a834a271..e92971a6 100644 --- a/backend/tests/test_composite.c +++ b/backend/tests/test_composite.c @@ -4312,7 +4312,7 @@ static void test_input(const testCtx *const p_ctx) { testFinish(); } -/* #181 Christian Hartlage OSS-Fuzz and #300 Andre Maute */ +/* #181 Christian Hartlage OSS-Fuzz, and #300 & #359 Andre Maute */ static void test_fuzz(const testCtx *const p_ctx) { int debug = p_ctx->debug; @@ -4320,6 +4320,7 @@ static void test_fuzz(const testCtx *const p_ctx) { int symbology; int input_mode; int option_1; + int warn_level; const char *data; int length; const char *composite; @@ -4330,21 +4331,22 @@ static void test_fuzz(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_EAN13_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, - /* 1*/ { BARCODE_EANX_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, - /* 2*/ { BARCODE_UPCA_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, - /* 3*/ { BARCODE_UPCE_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, - /* 4*/ { BARCODE_EAN8_CC, -1, -1, "+12345", -1, "[21]A12345678", ZINT_WARN_NONCOMPLIANT , 0, "Warning 292: EAN-8 with add-on is non-standard (linear component)", "BWIPP checks for proper EAN data" }, - /* 5*/ { BARCODE_EANX_CC, -1, -1, "+12345", -1, "[21]A12345678", ZINT_WARN_NONCOMPLIANT , 0, "Warning 292: EAN-8 with add-on is non-standard (linear component)", "BWIPP checks for proper EAN data" }, - /* 6*/ { BARCODE_EAN8_CC, -1, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 6 too long (maximum 5) (linear component)", "" }, - /* 7*/ { BARCODE_EANX_CC, -1, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 6 too long (maximum 5) (linear component)", "" }, - /* 8*/ { BARCODE_EAN8_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA, 1, "Error 284: Invalid character at position 1 in input (digits and \"+\" or space only) (linear component)", "" }, /* #300 (#5), Andre Maute (`dbar_date()` not checking length + other non-checks) */ - /* 9*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA, 1, "Error 284: Invalid character at position 1 in input (digits and \"+\" or space only) (linear component)", "" }, /* #300 (#5), Andre Maute (`dbar_date()` not checking length + other non-checks) */ - /* 10*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\153\153\153\153\153\153\153\153\163", -1, "()90", ZINT_ERROR_TOO_LONG, 1, "Error 283: Input length 46 too long (maximum 19) (linear component)", "" }, /* #300 (#6), Andre Maute (`dbar_date()` not checking length + other non-checks) */ - /* 11*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_INVALID_DATA, 1, "Error 253: Malformed AI in input (brackets don't match) (2D component)", "" }, /* #300 (#11), Andre Maute (`gs1_verify()` not checking length on resolve AI data loop) */ - /* 12*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_INVALID_DATA, 1, "Error 253: Malformed AI in input (brackets don't match) (2D component)", "" }, /* #300 (#11 with EANX_CC) */ - /* 13*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, "[]28", -1, "[]RRR___________________KKKRRR0000", 0, 1, "", "" }, /* #300 (#13), Andre Maute (`calc_padding_ccc()` dividing by zero when linear width == 68) */ - /* 14*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, "[]2", -1, "[]RRR___________________KKKRRR0000", 0, 1, "", "" }, /* #300 (#13 shortened to min linear input (but same linear width 68)) */ + /* 0*/ { BARCODE_EAN13_CC, -1, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, + /* 1*/ { BARCODE_EANX_CC, -1, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, + /* 2*/ { BARCODE_UPCA_CC, -1, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, + /* 3*/ { BARCODE_UPCE_CC, -1, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 18 too long (maximum 5) (linear component)", "" }, + /* 4*/ { BARCODE_EAN8_CC, -1, -1, -1, "+12345", -1, "[21]A12345678", ZINT_WARN_NONCOMPLIANT , 0, "Warning 292: EAN-8 with add-on is non-standard (linear component)", "BWIPP checks for proper EAN data" }, + /* 5*/ { BARCODE_EANX_CC, -1, -1, -1, "+12345", -1, "[21]A12345678", ZINT_WARN_NONCOMPLIANT , 0, "Warning 292: EAN-8 with add-on is non-standard (linear component)", "BWIPP checks for proper EAN data" }, + /* 6*/ { BARCODE_EAN8_CC, -1, -1, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 6 too long (maximum 5) (linear component)", "" }, + /* 7*/ { BARCODE_EANX_CC, -1, -1, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "Error 297: Input add-on length 6 too long (maximum 5) (linear component)", "" }, + /* 8*/ { BARCODE_EAN8_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, -1, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA, 1, "Error 284: Invalid character at position 1 in input (digits and \"+\" or space only) (linear component)", "" }, /* #300 (#5), Andre Maute (`dbar_date()` not checking length + other non-checks) */ + /* 9*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, -1, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA, 1, "Error 284: Invalid character at position 1 in input (digits and \"+\" or space only) (linear component)", "" }, /* #300 (#5), Andre Maute (`dbar_date()` not checking length + other non-checks) */ + /* 10*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\153\153\153\153\153\153\153\153\163", -1, "()90", ZINT_ERROR_TOO_LONG, 1, "Error 283: Input length 46 too long (maximum 19) (linear component)", "" }, /* #300 (#6), Andre Maute (`dbar_date()` not checking length + other non-checks) */ + /* 11*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_INVALID_DATA, 1, "Error 253: Malformed AI in input (brackets don't match) (2D component)", "" }, /* #300 (#11), Andre Maute (`gs1_verify()` not checking length on resolve AI data loop) */ + /* 12*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_INVALID_DATA, 1, "Error 253: Malformed AI in input (brackets don't match) (2D component)", "" }, /* #300 (#11 with EANX_CC) */ + /* 13*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, -1, "[]28", -1, "[]RRR___________________KKKRRR0000", 0, 1, "", "" }, /* #300 (#13), Andre Maute (`calc_padding_ccc()` dividing by zero when linear width == 68) */ + /* 14*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, -1, "[]2", -1, "[]RRR___________________KKKRRR0000", 0, 1, "", "" }, /* #300 (#13 shortened to min linear input (but same linear width 68)) */ + /* 15*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, 1802201856, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\153\153\153\153\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\000\100\001\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()90", ZINT_ERROR_TOO_LONG, 1, "Error 283: Input length 46 too long (maximum 19) (linear component)", "" }, /* #359, Andre Maute (assert(warn_level < ZINT_ERROR)) */ }; const int data_size = ARRAY_SIZE(data); int i, length, composite_length, ret; @@ -4366,6 +4368,9 @@ static void test_fuzz(const testCtx *const p_ctx) { length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, data[i].option_1, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); + if (data[i].warn_level != -1) { + symbol->warn_level = data[i].warn_level; + } assert_zero(length >= 128, "i:%d length %d >= 128\n", i, length); strcpy(symbol->primary, data[i].data); diff --git a/backend/tests/test_library.c b/backend/tests/test_library.c index 4b6e46f5..83e7eaec 100644 --- a/backend/tests/test_library.c +++ b/backend/tests/test_library.c @@ -2306,7 +2306,9 @@ static void test_error_tag(const testCtx *const p_ctx) { if (testContinue(p_ctx, i)) continue; if (data[i].debug_test) symbol->debug |= ZINT_DEBUG_TEST; - symbol->warn_level = data[i].warn_level; + if (data[i].warn_level != -1) { + symbol->warn_level = data[i].warn_level; + } ret = zint_test_error_tag(data[i].error_number, symbol, -1, data[i].data); assert_equal(ret, data[i].ret, "i:%d ret %d != %d\n", i, ret, data[i].ret); diff --git a/backend/zint.h b/backend/zint.h index 109bef0c..86cd2522 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -361,6 +361,7 @@ extern "C" { /* Warning level (`symbol->warn_level`) */ #define WARN_DEFAULT 0 /* Default behaviour */ #define WARN_FAIL_ALL 2 /* Treat warning as error */ +#define WARN_LEVEL_MASK 2 /* Mask of valid values */ /* Capability flags (ZBarcode_Cap() `cap_flag`) */ #define ZINT_CAP_HRT 0x0001 /* Prints Human Readable Text? */