@@ -129,6 +129,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
129
129
bufsize_t cell_matched = 1 , pipe_matched = 1 , offset ;
130
130
int expect_more_cells = 1 ;
131
131
int row_end_offset = 0 ;
132
+ int int_overflow_abort = 0 ;
132
133
133
134
row = (table_row * )parser -> mem -> calloc (1 , sizeof (table_row ));
134
135
row -> n_columns = 0 ;
@@ -161,6 +162,12 @@ static table_row *row_from_string(cmark_syntax_extension *self,
161
162
++ cell -> internal_offset ;
162
163
}
163
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
+ }
164
171
row -> n_columns += 1 ;
165
172
row -> cells = cmark_llist_append (parser -> mem , row -> cells , cell );
166
173
}
@@ -194,7 +201,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
194
201
}
195
202
}
196
203
197
- if (offset != len || row -> n_columns == 0 ) {
204
+ if (offset != len || row -> n_columns == 0 || int_overflow_abort ) {
198
205
free_table_row (parser -> mem , row );
199
206
row = NULL ;
200
207
}
@@ -241,6 +248,11 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
241
248
marker_row = row_from_string (self , parser ,
242
249
input + cmark_parser_get_first_nonspace (parser ),
243
250
len - cmark_parser_get_first_nonspace (parser ));
251
+ // assert may be optimized out, don't rely on it for security boundaries
252
+ if (!marker_row ) {
253
+ return parent_container ;
254
+ }
255
+
244
256
assert (marker_row );
245
257
246
258
cmark_arena_push ();
@@ -264,6 +276,12 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
264
276
len - cmark_parser_get_first_nonspace (parser ));
265
277
header_row = row_from_string (self , parser , (unsigned char * )parent_string ,
266
278
(int )strlen (parent_string ));
279
+ // row_from_string can return NULL, add additional check to ensure n_columns match
280
+ if (!marker_row || !header_row || header_row -> n_columns != marker_row -> n_columns ) {
281
+ free_table_row (parser -> mem , marker_row );
282
+ free_table_row (parser -> mem , header_row );
283
+ return parent_container ;
284
+ }
267
285
}
268
286
269
287
if (!cmark_node_set_type (parent_container , CMARK_NODE_TABLE )) {
@@ -281,8 +299,10 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
281
299
parent_container -> as .opaque = parser -> mem -> calloc (1 , sizeof (node_table ));
282
300
set_n_table_columns (parent_container , header_row -> n_columns );
283
301
302
+ // allocate alignments based on marker_row->n_columns
303
+ // since we populate the alignments array based on marker_row->cells
284
304
uint8_t * alignments =
285
- (uint8_t * )parser -> mem -> calloc (header_row -> n_columns , sizeof (uint8_t ));
305
+ (uint8_t * )parser -> mem -> calloc (marker_row -> n_columns , sizeof (uint8_t ));
286
306
cmark_llist * it = marker_row -> cells ;
287
307
for (i = 0 ; it ; it = it -> next , ++ i ) {
288
308
node_cell * node = (node_cell * )it -> data ;
@@ -351,6 +371,12 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
351
371
row = row_from_string (self , parser , input + cmark_parser_get_first_nonspace (parser ),
352
372
len - cmark_parser_get_first_nonspace (parser ));
353
373
374
+ if (!row ) {
375
+ // clean up the dangling node
376
+ cmark_node_free (table_row_block );
377
+ return NULL ;
378
+ }
379
+
354
380
{
355
381
cmark_llist * tmp ;
356
382
int i , table_columns = get_n_table_columns (parent_container );
0 commit comments