Skip to content

Commit fcfae7e

Browse files
committed
node: bounds-check in cmark_set_cstr and propagate error status
Change cmark_set_cstr to return success/failure status and add a bounds check for inputs exceeding the buffer limit. Callers propagate the status. Define BUFSIZE_MAX in buffer.h and use it in buffer.c and node.c. Document custom allocator contract in cmark.h.
1 parent b320f40 commit fcfae7e

4 files changed

Lines changed: 31 additions & 24 deletions

File tree

src/buffer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
4040
if (target_size < buf->asize)
4141
return;
4242

43-
if (target_size > (bufsize_t)(INT32_MAX / 2)) {
43+
if (target_size > (bufsize_t)(BUFSIZE_MAX / 2)) {
4444
fprintf(stderr,
4545
"[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n",
46-
(INT32_MAX / 2));
46+
(BUFSIZE_MAX / 2));
4747
abort();
4848
}
4949

src/buffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414
#endif
1515

1616
typedef int32_t bufsize_t;
17+
#define BUFSIZE_MAX INT32_MAX
1718

1819
typedef struct {
1920
cmark_mem *mem;

src/cmark.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ typedef struct cmark_iter cmark_iter;
9393
*/
9494

9595
/** Defines the memory allocation functions to be used by CMark
96-
* when parsing and allocating a document tree
96+
* when parsing and allocating a document tree. Allocation functions
97+
* must not return NULL; if they are unable to satisfy a request,
98+
* they must abort the program (e.g. by calling abort()).
9799
*/
98100
typedef struct cmark_mem {
99101
void *(*calloc)(size_t, size_t);

src/node.c

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -264,24 +264,34 @@ cmark_node *cmark_node_last_child(cmark_node *node) {
264264
}
265265
}
266266

267-
static bufsize_t cmark_set_cstr(cmark_mem *mem, unsigned char **dst,
268-
const char *src) {
267+
static int cmark_set_cstr(cmark_mem *mem, unsigned char **dst,
268+
bufsize_t *len, const char *src) {
269269
unsigned char *old = *dst;
270-
bufsize_t len;
270+
unsigned char *new_str = NULL;
271+
bufsize_t new_len = 0;
271272

272273
if (src && src[0]) {
273-
len = (bufsize_t)strlen(src);
274-
*dst = (unsigned char *)mem->realloc(NULL, len + 1);
275-
memcpy(*dst, src, len + 1);
274+
size_t srclen = strlen(src);
275+
if (srclen > (size_t)BUFSIZE_MAX - 1) {
276+
return 0;
277+
}
278+
new_str = (unsigned char *)mem->realloc(NULL, srclen + 1);
279+
memcpy(new_str, src, srclen + 1);
280+
new_len = (bufsize_t)srclen;
276281
} else {
277-
len = 0;
278-
*dst = NULL;
282+
new_len = 0;
283+
new_str = NULL;
284+
}
285+
286+
*dst = new_str;
287+
if (len) {
288+
*len = new_len;
279289
}
280290
if (old) {
281291
mem->free(old);
282292
}
283293

284-
return len;
294+
return 1;
285295
}
286296

287297
void *cmark_node_get_user_data(cmark_node *node) {
@@ -331,8 +341,7 @@ int cmark_node_set_literal(cmark_node *node, const char *content) {
331341
case CMARK_NODE_HTML_INLINE:
332342
case CMARK_NODE_CODE:
333343
case CMARK_NODE_CODE_BLOCK:
334-
node->len = cmark_set_cstr(node->mem, &node->data, content);
335-
return 1;
344+
return cmark_set_cstr(node->mem, &node->data, &node->len, content);
336345

337346
default:
338347
break;
@@ -500,8 +509,7 @@ int cmark_node_set_fence_info(cmark_node *node, const char *info) {
500509
}
501510

502511
if (node->type == CMARK_NODE_CODE_BLOCK) {
503-
cmark_set_cstr(node->mem, &node->as.code.info, info);
504-
return 1;
512+
return cmark_set_cstr(node->mem, &node->as.code.info, NULL, info);
505513
} else {
506514
return 0;
507515
}
@@ -531,8 +539,7 @@ int cmark_node_set_url(cmark_node *node, const char *url) {
531539
switch (node->type) {
532540
case CMARK_NODE_LINK:
533541
case CMARK_NODE_IMAGE:
534-
cmark_set_cstr(node->mem, &node->as.link.url, url);
535-
return 1;
542+
return cmark_set_cstr(node->mem, &node->as.link.url, NULL, url);
536543
default:
537544
break;
538545
}
@@ -564,8 +571,7 @@ int cmark_node_set_title(cmark_node *node, const char *title) {
564571
switch (node->type) {
565572
case CMARK_NODE_LINK:
566573
case CMARK_NODE_IMAGE:
567-
cmark_set_cstr(node->mem, &node->as.link.title, title);
568-
return 1;
574+
return cmark_set_cstr(node->mem, &node->as.link.title, NULL, title);
569575
default:
570576
break;
571577
}
@@ -597,8 +603,7 @@ int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
597603
switch (node->type) {
598604
case CMARK_NODE_CUSTOM_INLINE:
599605
case CMARK_NODE_CUSTOM_BLOCK:
600-
cmark_set_cstr(node->mem, &node->as.custom.on_enter, on_enter);
601-
return 1;
606+
return cmark_set_cstr(node->mem, &node->as.custom.on_enter, NULL, on_enter);
602607
default:
603608
break;
604609
}
@@ -630,8 +635,7 @@ int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
630635
switch (node->type) {
631636
case CMARK_NODE_CUSTOM_INLINE:
632637
case CMARK_NODE_CUSTOM_BLOCK:
633-
cmark_set_cstr(node->mem, &node->as.custom.on_exit, on_exit);
634-
return 1;
638+
return cmark_set_cstr(node->mem, &node->as.custom.on_exit, NULL, on_exit);
635639
default:
636640
break;
637641
}

0 commit comments

Comments
 (0)