Skip to content

Commit 78e3f1d

Browse files
Fix GHSL-2022-091: use growable array rather than appending to a singly-linked-list for better efficiency.
1 parent 9d57d8a commit 78e3f1d

File tree

1 file changed

+38
-34
lines changed

1 file changed

+38
-34
lines changed

extensions/table.c

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414
cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
1515
CMARK_NODE_TABLE_CELL;
1616

17+
typedef struct {
18+
cmark_strbuf *buf;
19+
int start_offset, end_offset, internal_offset;
20+
} node_cell;
21+
1722
typedef struct {
1823
uint16_t n_columns;
1924
int paragraph_offset;
20-
cmark_llist *cells;
25+
node_cell *cells;
2126
} table_row;
2227

2328
typedef struct {
@@ -29,24 +34,24 @@ typedef struct {
2934
bool is_header;
3035
} node_table_row;
3136

32-
typedef struct {
33-
cmark_strbuf *buf;
34-
int start_offset, end_offset, internal_offset;
35-
} node_cell;
36-
37-
static void free_table_cell(cmark_mem *mem, void *data) {
38-
node_cell *cell = (node_cell *)data;
37+
static void free_table_cell(cmark_mem *mem, node_cell *cell) {
3938
cmark_strbuf_free((cmark_strbuf *)cell->buf);
4039
mem->free(cell->buf);
41-
mem->free(cell);
40+
}
41+
42+
static void free_row_cells(cmark_mem *mem, table_row *row) {
43+
while (row->n_columns > 0) {
44+
free_table_cell(mem, &row->cells[--row->n_columns]);
45+
}
46+
mem->free(row->cells);
47+
row->cells = NULL;
4248
}
4349

4450
static void free_table_row(cmark_mem *mem, table_row *row) {
4551
if (!row)
4652
return;
4753

48-
cmark_llist_free_full(mem, row->cells, (cmark_free_func)free_table_cell);
49-
54+
free_row_cells(mem, row);
5055
mem->free(row);
5156
}
5257

@@ -152,24 +157,29 @@ static table_row *row_from_string(cmark_syntax_extension *self,
152157
cell_matched);
153158
cmark_strbuf_trim(cell_buf);
154159

155-
node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
160+
const uint32_t n_columns = row->n_columns + 1;
161+
// realloc when n_columns is a power of 2
162+
if ((n_columns & (n_columns-1)) == 0) {
163+
// make sure we never wrap row->n_columns
164+
// offset will != len and our exit will clean up as intended
165+
if (n_columns > UINT16_MAX) {
166+
int_overflow_abort = 1;
167+
break;
168+
}
169+
// Use realloc to double the size of the buffer.
170+
row->cells = (node_cell *)parser->mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell));
171+
}
172+
row->n_columns = n_columns;
173+
node_cell *cell = &row->cells[n_columns-1];
156174
cell->buf = cell_buf;
157175
cell->start_offset = offset;
158176
cell->end_offset = offset + cell_matched - 1;
177+
cell->internal_offset = 0;
159178

160179
while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
161180
--cell->start_offset;
162181
++cell->internal_offset;
163182
}
164-
165-
// make sure we never wrap row->n_columns
166-
// offset will != len and our exit will clean up as intended
167-
if (row->n_columns == UINT16_MAX) {
168-
int_overflow_abort = 1;
169-
break;
170-
}
171-
row->n_columns += 1;
172-
row->cells = cmark_llist_append(parser->mem, row->cells, cell);
173183
}
174184

175185
offset += cell_matched + pipe_matched;
@@ -187,9 +197,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
187197
if (row_end_offset && offset != len) {
188198
row->paragraph_offset = offset;
189199

190-
cmark_llist_free_full(parser->mem, row->cells, (cmark_free_func)free_table_cell);
191-
row->cells = NULL;
192-
row->n_columns = 0;
200+
free_row_cells(parser->mem, row);
193201

194202
// Scan past the (optional) leading pipe.
195203
offset += scan_table_cell_end(string, len, offset);
@@ -303,9 +311,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
303311
// since we populate the alignments array based on marker_row->cells
304312
uint8_t *alignments =
305313
(uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
306-
cmark_llist *it = marker_row->cells;
307-
for (i = 0; it; it = it->next, ++i) {
308-
node_cell *node = (node_cell *)it->data;
314+
for (i = 0; i < marker_row->n_columns; ++i) {
315+
node_cell *node = &marker_row->cells[i];
309316
bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':';
310317

311318
if (left && right)
@@ -328,10 +335,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
328335
ntr->is_header = true;
329336

330337
{
331-
cmark_llist *tmp;
332-
333-
for (tmp = header_row->cells; tmp; tmp = tmp->next) {
334-
node_cell *cell = (node_cell *) tmp->data;
338+
for (i = 0; i < header_row->n_columns; ++i) {
339+
node_cell *cell = &header_row->cells[i];
335340
cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
336341
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
337342
header_cell->start_line = header_cell->end_line = parent_container->start_line;
@@ -378,11 +383,10 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
378383
}
379384

380385
{
381-
cmark_llist *tmp;
382386
int i, table_columns = get_n_table_columns(parent_container);
383387

384-
for (tmp = row->cells, i = 0; tmp && i < table_columns; tmp = tmp->next, ++i) {
385-
node_cell *cell = (node_cell *) tmp->data;
388+
for (i = 0; i < row->n_columns && i < table_columns; ++i) {
389+
node_cell *cell = &row->cells[i];
386390
cmark_node *node = cmark_parser_add_child(parser, table_row_block,
387391
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
388392
node->internal_offset = cell->internal_offset;

0 commit comments

Comments
 (0)