@@ -129,6 +129,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
129129 bufsize_t cell_matched = 1 , pipe_matched = 1 , offset ;
130130 int expect_more_cells = 1 ;
131131 int row_end_offset = 0 ;
132+ int int_overflow_abort = 0 ;
132133
133134 row = (table_row * )parser -> mem -> calloc (1 , sizeof (table_row ));
134135 row -> n_columns = 0 ;
@@ -161,6 +162,12 @@ static table_row *row_from_string(cmark_syntax_extension *self,
161162 ++ cell -> internal_offset ;
162163 }
163164
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+ }
164171 row -> n_columns += 1 ;
165172 row -> cells = cmark_llist_append (parser -> mem , row -> cells , cell );
166173 }
@@ -194,7 +201,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
194201 }
195202 }
196203
197- if (offset != len || row -> n_columns == 0 ) {
204+ if (offset != len || row -> n_columns == 0 || int_overflow_abort ) {
198205 free_table_row (parser -> mem , row );
199206 row = NULL ;
200207 }
@@ -241,6 +248,11 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
241248 marker_row = row_from_string (self , parser ,
242249 input + cmark_parser_get_first_nonspace (parser ),
243250 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+
244256 assert (marker_row );
245257
246258 cmark_arena_push ();
@@ -264,6 +276,12 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
264276 len - cmark_parser_get_first_nonspace (parser ));
265277 header_row = row_from_string (self , parser , (unsigned char * )parent_string ,
266278 (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+ }
267285 }
268286
269287 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,
281299 parent_container -> as .opaque = parser -> mem -> calloc (1 , sizeof (node_table ));
282300 set_n_table_columns (parent_container , header_row -> n_columns );
283301
302+ // allocate alignments based on marker_row->n_columns
303+ // since we populate the alignments array based on marker_row->cells
284304 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 ));
286306 cmark_llist * it = marker_row -> cells ;
287307 for (i = 0 ; it ; it = it -> next , ++ i ) {
288308 node_cell * node = (node_cell * )it -> data ;
@@ -351,6 +371,12 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
351371 row = row_from_string (self , parser , input + cmark_parser_get_first_nonspace (parser ),
352372 len - cmark_parser_get_first_nonspace (parser ));
353373
374+ if (!row ) {
375+ // clean up the dangling node
376+ cmark_node_free (table_row_block );
377+ return NULL ;
378+ }
379+
354380 {
355381 cmark_llist * tmp ;
356382 int i , table_columns = get_n_table_columns (parent_container );
0 commit comments