Skip to content

gcc 13.2.0: bogus Wstringop-overflow (3) in qrencode (-O3 only) #1540

Open
@evoskuil

Description

@evoskuil
static unsigned char *QRspec_createFrame(int version)
{
	unsigned char *frame, *p, *q;
	int width;
	int x, y;
	unsigned int verinfo, v;

	width = qrspecCapacity[version].width;
	frame = (unsigned char *)malloc((size_t)(width * width));
	if(frame == NULL) return NULL;

	memset(frame, 0, (size_t)(width * width));
	/* Finder pattern */
	putFinderPattern(frame, width, 0, 0);
	putFinderPattern(frame, width, width - 7, 0);
	putFinderPattern(frame, width, 0, width - 7);
	/* Separator */
	p = frame;
	q = frame + width * (width - 7);
	for(y = 0; y < 7; y++) {
		p[7] = 0xc0;
		p[width - 8] = 0xc0;
		q[7] = 0xc0;
		p += width;
		q += width;
	}
	memset(frame + width * 7, 0xc0, 8);
	memset(frame + width * 8 - 8, 0xc0, 8);
	memset(frame + width * (width - 8), 0xc0, 8);
	...
}

The warning assumes that in the above code width = 1 is possible.

warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
447 | p[width - 8] = 0xc0;
...
note: at offset -7 into destination object of size [0, 2147483647] allocated by 'malloc'
434 | frame = (unsigned char *)malloc((size_t)(width * width));

The code clearly assumes otherwise. This is a perfectly safe and constant assumption because the nonzero minimum value of width is 21.

typedef struct {
	int width;      /* < Edge length of the symbol */
	int words;      /* < Data capacity (bytes) */
	int remainder;  /* < Remainder bit (bits) */
	int ec[4];      /* < Number of ECC code (bytes) */
} QRspec_Capacity;

/**
 * Table of the capacity of symbols
 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
 */
static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = {
	{  0,    0, 0, {   0,    0,    0,    0}},
	{ 21,   26, 0, {   7,   10,   13,   17}}, /* 1 */
	{ 25,   44, 7, {  10,   16,   22,   28}},
	{ 29,   70, 7, {  15,   26,   36,   44}},
	{ 33,  100, 7, {  20,   36,   52,   64}},
	{ 37,  134, 7, {  26,   48,   72,   88}}, /* 5 */
	{ 41,  172, 7, {  36,   64,   96,  112}},
	{ 45,  196, 0, {  40,   72,  108,  130}},
	{ 49,  242, 0, {  48,   88,  132,  156}},
	{ 53,  292, 0, {  60,  110,  160,  192}},
	{ 57,  346, 0, {  72,  130,  192,  224}}, /* 10 */
	{ 61,  404, 0, {  80,  150,  224,  264}},
	{ 65,  466, 0, {  96,  176,  260,  308}},
	{ 69,  532, 0, { 104,  198,  288,  352}},
	{ 73,  581, 3, { 120,  216,  320,  384}},
	{ 77,  655, 3, { 132,  240,  360,  432}}, /* 15 */
	{ 81,  733, 3, { 144,  280,  408,  480}},
	{ 85,  815, 3, { 168,  308,  448,  532}},
	{ 89,  901, 3, { 180,  338,  504,  588}},
	{ 93,  991, 3, { 196,  364,  546,  650}},
	{ 97, 1085, 3, { 224,  416,  600,  700}}, /* 20 */
	{101, 1156, 4, { 224,  442,  644,  750}},
	{105, 1258, 4, { 252,  476,  690,  816}},
	{109, 1364, 4, { 270,  504,  750,  900}},
	{113, 1474, 4, { 300,  560,  810,  960}},
	{117, 1588, 4, { 312,  588,  870, 1050}}, /* 25 */
	{121, 1706, 4, { 336,  644,  952, 1110}},
	{125, 1828, 4, { 360,  700, 1020, 1200}},
	{129, 1921, 3, { 390,  728, 1050, 1260}},
	{133, 2051, 3, { 420,  784, 1140, 1350}},
	{137, 2185, 3, { 450,  812, 1200, 1440}}, /* 30 */
	{141, 2323, 3, { 480,  868, 1290, 1530}},
	{145, 2465, 3, { 510,  924, 1350, 1620}},
	{149, 2611, 3, { 540,  980, 1440, 1710}},
	{153, 2761, 3, { 570, 1036, 1530, 1800}},
	{157, 2876, 0, { 570, 1064, 1590, 1890}}, /* 35 */
	{161, 3034, 0, { 600, 1120, 1680, 1980}},
	{165, 3196, 0, { 630, 1204, 1770, 2100}},
	{169, 3362, 0, { 660, 1260, 1860, 2220}},
	{173, 3532, 0, { 720, 1316, 1950, 2310}},
	{177, 3706, 0, { 750, 1372, 2040, 2430}}  /* 40 */
};
In function 'QRspec_createFrame',
    inlined from 'QRspec_newFrame' at src/wallet/addresses/qrencode/qrspec.c:513:9:
src/wallet/addresses/qrencode/qrspec.c:447:30: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
  447 |                 p[width - 8] = 0xc0;
      |                 ~~~~~~~~~~~~~^~~~~~
src/wallet/addresses/qrencode/qrspec.c:434:34: note: at offset -7 into destination object of size [0, 2147483647] allocated by 'malloc'
  434 |         frame = (unsigned char *)malloc((size_t)(width * width));
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions