mirror of
https://git.code.sf.net/p/zint/code
synced 2025-05-27 13:34:19 -04:00
QRCODE: fix out-of-bounds crash due to incorrect mode costings for
GS1 percents in `qr_in_alpha()`, ticket #300, props Andre Maute; also defensively re-calc version 40 mode to prevent possible further crashes common: move `debug_print_escape()` from library to common
This commit is contained in:
parent
db92c7de57
commit
888db0bf00
13 changed files with 445 additions and 205 deletions
64
backend/qr.c
64
backend/qr.c
|
@ -94,41 +94,54 @@ static int qr_in_numeric(const unsigned int ddata[], const int length, const int
|
|||
/* Whether in alpha or not. If in alpha, *p_end is set to position after alpha, and *p_cost is set to per-alpha cost.
|
||||
* For GS1, *p_pcent set if 2nd char percent */
|
||||
static int qr_in_alpha(const unsigned int ddata[], const int length, const int in_posn,
|
||||
unsigned int *p_end, unsigned int *p_cost, unsigned int *p_pcent, unsigned int gs1) {
|
||||
unsigned int *p_end, unsigned int *p_cost, unsigned int *p_pcent, unsigned int *p_pccnt,
|
||||
unsigned int gs1) {
|
||||
const int last = in_posn + 1 == length;
|
||||
int two_alphas;
|
||||
|
||||
/* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */
|
||||
if (in_posn < (int) *p_end) {
|
||||
if (gs1 && *p_pcent) {
|
||||
/* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */
|
||||
two_alphas = in_posn < length - 1 && qr_is_alpha(ddata[in_posn + 1], gs1);
|
||||
*p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
|
||||
two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1);
|
||||
/* Uneven percents means this will fit evenly in alpha pair */
|
||||
*p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */;
|
||||
*p_pcent = 0;
|
||||
} else {
|
||||
/* As above, uneven percents means will fit in alpha pair */
|
||||
*p_cost = !last || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */
|
||||
if (!qr_is_alpha(ddata[in_posn], gs1)) {
|
||||
*p_end = 0;
|
||||
*p_pcent = 0;
|
||||
*p_pccnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1);
|
||||
|
||||
if (gs1 && ddata[in_posn] == '%') { /* Must double-up so counts as 2 chars */
|
||||
*p_end = in_posn + 1;
|
||||
*p_cost = 66; /* 11 * QR_MULT */
|
||||
*p_pcent = 0;
|
||||
(*p_pccnt)++;
|
||||
/* Uneven percents means will fit in alpha pair */
|
||||
*p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */;
|
||||
return 1;
|
||||
}
|
||||
|
||||
two_alphas = in_posn < length - 1 && qr_is_alpha(ddata[in_posn + 1], gs1);
|
||||
|
||||
*p_end = two_alphas ? in_posn + 2 : in_posn + 1;
|
||||
*p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
|
||||
*p_pcent = two_alphas && gs1 && ddata[in_posn + 1] == '%'; /* 2nd char is percent */
|
||||
*p_pccnt += *p_pcent; /* No-op unless `gs1` */
|
||||
/* Uneven percents means will fit in alpha pair */
|
||||
*p_cost = two_alphas || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*#define QR_DEBUG_DEFINE_MODE*/ /* For debugging costings */
|
||||
|
||||
/* Indexes into qr_mode_types array (and state array) */
|
||||
#define QR_N 0 /* Numeric */
|
||||
#define QR_A 1 /* Alphanumeric */
|
||||
|
@ -146,13 +159,14 @@ static const char qr_mode_types[] = { 'N', 'A', 'B', 'K', '\0' }; /* Must be in
|
|||
#define QR_A_END 7 /* Alpha end index */
|
||||
#define QR_A_COST 8 /* Alpha cost */
|
||||
#define QR_A_PCENT 9 /* Alpha 2nd char percent (GS1-specific) */
|
||||
#define QR_A_PCCNT 10 /* Alpha total percent count (GS1-specific) */
|
||||
|
||||
/* Costs set to this for invalid MICROQR modes for versions M1 and M2.
|
||||
* 128 is the max number of data bits for M4-L (ISO/IEC 18004:2015 Table 7) */
|
||||
#define QR_MICROQR_MAX 774 /* (128 + 1) * QR_MULT */
|
||||
|
||||
/* Initial mode costs */
|
||||
static unsigned int *qr_head_costs(unsigned int state[10]) {
|
||||
static unsigned int *qr_head_costs(unsigned int state[11]) {
|
||||
static const unsigned int head_costs[7][QR_NUM_MODES] = {
|
||||
/* N A B K */
|
||||
{ (10 + 4) * QR_MULT, (9 + 4) * QR_MULT, (8 + 4) * QR_MULT, (8 + 4) * QR_MULT, }, /* QR */
|
||||
|
@ -206,10 +220,10 @@ static void qr_define_mode(char mode[], const unsigned int ddata[], const int le
|
|||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
unsigned int state[10] = {
|
||||
unsigned int state[11] = {
|
||||
0 /*N*/, 0 /*A*/, 0 /*B*/, 0 /*K*/, /* Head/switch costs */
|
||||
0 /*version*/,
|
||||
0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/
|
||||
0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/, 0 /*alpha_pccnt*/
|
||||
};
|
||||
int m1, m2;
|
||||
|
||||
|
@ -230,6 +244,14 @@ static void qr_define_mode(char mode[], const unsigned int ddata[], const int le
|
|||
* bits needed to encode the entire string prefix of length i, and end in qr_mode_types[j] */
|
||||
memcpy(prev_costs, qr_head_costs(state), QR_NUM_MODES * sizeof(unsigned int));
|
||||
|
||||
#ifdef QR_DEBUG_DEFINE_MODE
|
||||
printf(" head");
|
||||
for (j = 0; j < QR_NUM_MODES; j++) {
|
||||
printf(" %c(%c)=%d", qr_mode_types[j], char_modes[j], prev_costs[j]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* Calculate costs using dynamic programming */
|
||||
for (i = 0, cm_i = 0; i < length; i++, cm_i += QR_NUM_MODES) {
|
||||
memset(cur_costs, 0, QR_NUM_MODES * sizeof(unsigned int));
|
||||
|
@ -247,7 +269,8 @@ static void qr_define_mode(char mode[], const unsigned int ddata[], const int le
|
|||
cur_costs[QR_N] = prev_costs[QR_N] + state[QR_N_COST];
|
||||
char_modes[cm_i + QR_N] = 'N';
|
||||
}
|
||||
if (qr_in_alpha(ddata, length, i, &state[QR_A_END], &state[QR_A_COST], &state[QR_A_PCENT], gs1)) {
|
||||
if (qr_in_alpha(ddata, length, i, &state[QR_A_END], &state[QR_A_COST], &state[QR_A_PCENT],
|
||||
&state[QR_A_PCCNT], gs1)) {
|
||||
cur_costs[QR_A] = prev_costs[QR_A] + (m1 ? QR_MICROQR_MAX : state[QR_A_COST]);
|
||||
char_modes[cm_i + QR_A] = 'A';
|
||||
}
|
||||
|
@ -268,6 +291,13 @@ static void qr_define_mode(char mode[], const unsigned int ddata[], const int le
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef QR_DEBUG_DEFINE_MODE
|
||||
printf(" curr");
|
||||
for (j = 0; j < QR_NUM_MODES; j++) {
|
||||
printf(" %c(%c)=%d", qr_mode_types[j], char_modes[cm_i + j], cur_costs[j]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
memcpy(prev_costs, cur_costs, QR_NUM_MODES * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
|
@ -1725,8 +1755,18 @@ INTERNAL int qrcode(struct zint_symbol *symbol, struct zint_seg segs[], const in
|
|||
}
|
||||
}
|
||||
if (autosize != 40) {
|
||||
/* Save version 40 estimate in case incorrect costings in `qr_define_mode()` lead to its `mode` being better
|
||||
than current lower version one */
|
||||
prev_est_binlen = est_binlen;
|
||||
est_binlen = qr_calc_binlen_segs(autosize, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/,
|
||||
gs1, debug_print);
|
||||
if (prev_est_binlen < est_binlen) { /* Shouldn't happen */
|
||||
assert(0); /* Not reached (hopefully) */
|
||||
/* Defensively use version 40 `mode` to avoid crashes (ticket #300) */
|
||||
est_binlen = qr_calc_binlen_segs(40, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/,
|
||||
gs1, debug_print);
|
||||
assert(est_binlen == prev_est_binlen);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now see if the optimised binary will fit in a smaller symbol. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue