From c3e858e73a1b6badeccc0c2ba6b36b1016fadf35 Mon Sep 17 00:00:00 2001 From: "siddharthtiwari155@yahoo.com" Date: Thu, 21 May 2026 18:09:40 +0530 Subject: [PATCH] node: bounds-check in cmark_set_cstr and propagate error status. --- src/buffer.c | 4 ++-- src/buffer.h | 1 + src/cmark.h | 4 +++- src/node.c | 46 +++++++++++++++++++++++++--------------------- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 80d09c24f..0c6d36941 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -40,10 +40,10 @@ void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) { if (target_size < buf->asize) return; - if (target_size > (bufsize_t)(INT32_MAX / 2)) { + if (target_size > (bufsize_t)(BUFSIZE_MAX / 2)) { fprintf(stderr, "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n", - (INT32_MAX / 2)); + (BUFSIZE_MAX / 2)); abort(); } diff --git a/src/buffer.h b/src/buffer.h index e6a085724..0d42dc59e 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -14,6 +14,7 @@ extern "C" { #endif typedef int32_t bufsize_t; +#define BUFSIZE_MAX INT32_MAX typedef struct { cmark_mem *mem; diff --git a/src/cmark.h b/src/cmark.h index 6626b0627..e7bab271d 100644 --- a/src/cmark.h +++ b/src/cmark.h @@ -93,7 +93,9 @@ typedef struct cmark_iter cmark_iter; */ /** Defines the memory allocation functions to be used by CMark - * when parsing and allocating a document tree + * when parsing and allocating a document tree. Allocation functions + * must not return NULL; if they are unable to satisfy a request, + * they must abort the program (e.g. by calling abort()). */ typedef struct cmark_mem { void *(*calloc)(size_t, size_t); diff --git a/src/node.c b/src/node.c index c1492545e..f30d18f25 100644 --- a/src/node.c +++ b/src/node.c @@ -264,24 +264,34 @@ cmark_node *cmark_node_last_child(cmark_node *node) { } } -static bufsize_t cmark_set_cstr(cmark_mem *mem, unsigned char **dst, - const char *src) { +static int cmark_set_cstr(cmark_mem *mem, unsigned char **dst, + bufsize_t *len, const char *src) { unsigned char *old = *dst; - bufsize_t len; + unsigned char *new_str = NULL; + bufsize_t new_len = 0; if (src && src[0]) { - len = (bufsize_t)strlen(src); - *dst = (unsigned char *)mem->realloc(NULL, len + 1); - memcpy(*dst, src, len + 1); + size_t srclen = strlen(src); + if (srclen > (size_t)BUFSIZE_MAX - 1) { + return 0; + } + new_str = (unsigned char *)mem->realloc(NULL, srclen + 1); + memcpy(new_str, src, srclen + 1); + new_len = (bufsize_t)srclen; } else { - len = 0; - *dst = NULL; + new_len = 0; + new_str = NULL; + } + + *dst = new_str; + if (len) { + *len = new_len; } if (old) { mem->free(old); } - return len; + return 1; } void *cmark_node_get_user_data(cmark_node *node) { @@ -331,8 +341,7 @@ int cmark_node_set_literal(cmark_node *node, const char *content) { case CMARK_NODE_HTML_INLINE: case CMARK_NODE_CODE: case CMARK_NODE_CODE_BLOCK: - node->len = cmark_set_cstr(node->mem, &node->data, content); - return 1; + return cmark_set_cstr(node->mem, &node->data, &node->len, content); default: break; @@ -500,8 +509,7 @@ int cmark_node_set_fence_info(cmark_node *node, const char *info) { } if (node->type == CMARK_NODE_CODE_BLOCK) { - cmark_set_cstr(node->mem, &node->as.code.info, info); - return 1; + return cmark_set_cstr(node->mem, &node->as.code.info, NULL, info); } else { return 0; } @@ -531,8 +539,7 @@ int cmark_node_set_url(cmark_node *node, const char *url) { switch (node->type) { case CMARK_NODE_LINK: case CMARK_NODE_IMAGE: - cmark_set_cstr(node->mem, &node->as.link.url, url); - return 1; + return cmark_set_cstr(node->mem, &node->as.link.url, NULL, url); default: break; } @@ -564,8 +571,7 @@ int cmark_node_set_title(cmark_node *node, const char *title) { switch (node->type) { case CMARK_NODE_LINK: case CMARK_NODE_IMAGE: - cmark_set_cstr(node->mem, &node->as.link.title, title); - return 1; + return cmark_set_cstr(node->mem, &node->as.link.title, NULL, title); default: break; } @@ -597,8 +603,7 @@ int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) { switch (node->type) { case CMARK_NODE_CUSTOM_INLINE: case CMARK_NODE_CUSTOM_BLOCK: - cmark_set_cstr(node->mem, &node->as.custom.on_enter, on_enter); - return 1; + return cmark_set_cstr(node->mem, &node->as.custom.on_enter, NULL, on_enter); default: break; } @@ -630,8 +635,7 @@ int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) { switch (node->type) { case CMARK_NODE_CUSTOM_INLINE: case CMARK_NODE_CUSTOM_BLOCK: - cmark_set_cstr(node->mem, &node->as.custom.on_exit, on_exit); - return 1; + return cmark_set_cstr(node->mem, &node->as.custom.on_exit, NULL, on_exit); default: break; }