summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2016-05-24 15:50:44 +0200
committerJohn MacFarlane <jgm@berkeley.edu>2016-06-06 15:39:05 -0700
commit42b07cc9c8d2e6251d190e5ea0d13fd66cb51e6d (patch)
tree493ffc6b16278c54da28645d96a9359717625576 /src
parent0eafc0af940646ab581e47e63090c1692a3525aa (diff)
cmake: Global handler for OOM situations
Diffstat (limited to 'src')
-rw-r--r--src/blocks.c59
-rw-r--r--src/buffer.c48
-rw-r--r--src/buffer.h18
-rw-r--r--src/chunk.h13
-rw-r--r--src/cmark.c30
-rw-r--r--src/cmark.h14
-rw-r--r--src/inlines.c39
-rw-r--r--src/iterator.c5
-rw-r--r--src/main.c3
-rw-r--r--src/memory.h12
-rw-r--r--src/node.c2
-rwxr-xr-xsrc/references.c20
12 files changed, 122 insertions, 141 deletions
diff --git a/src/blocks.c b/src/blocks.c
index c778c7a..07eacc6 100644
--- a/src/blocks.c
+++ b/src/blocks.c
@@ -48,15 +48,13 @@ static cmark_node *make_block(cmark_node_type tag, int start_line,
int start_column) {
cmark_node *e;
- e = (cmark_node *)calloc(1, sizeof(*e));
- if (e != NULL) {
- e->type = tag;
- e->open = true;
- e->start_line = start_line;
- e->start_column = start_column;
- e->end_line = start_line;
- cmark_strbuf_init(&e->string_content, 32);
- }
+ e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+ e->type = tag;
+ e->open = true;
+ e->start_line = start_line;
+ e->start_column = start_column;
+ e->end_line = start_line;
+ cmark_strbuf_init(&e->string_content, 32);
return e;
}
@@ -68,10 +66,10 @@ static cmark_node *make_document() {
}
cmark_parser *cmark_parser_new(int options) {
- cmark_parser *parser = (cmark_parser *)malloc(sizeof(cmark_parser));
+ cmark_parser *parser = (cmark_parser *)cmark_calloc(1, sizeof(cmark_parser));
cmark_node *document = make_document();
- cmark_strbuf *line = (cmark_strbuf *)malloc(sizeof(cmark_strbuf));
- cmark_strbuf *buf = (cmark_strbuf *)malloc(sizeof(cmark_strbuf));
+ cmark_strbuf *line = (cmark_strbuf *)cmark_calloc(1, sizeof(cmark_strbuf));
+ cmark_strbuf *buf = (cmark_strbuf *)cmark_calloc(1, sizeof(cmark_strbuf));
cmark_strbuf_init(line, 256);
cmark_strbuf_init(buf, 0);
@@ -395,17 +393,13 @@ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
if (!cmark_isspace(peek_at(input, pos))) {
return 0;
}
- data = (cmark_list *)calloc(1, sizeof(*data));
- if (data == NULL) {
- return 0;
- } else {
- data->marker_offset = 0; // will be adjusted later
- data->list_type = CMARK_BULLET_LIST;
- data->bullet_char = c;
- data->start = 1;
- data->delimiter = CMARK_PERIOD_DELIM;
- data->tight = false;
- }
+ data = (cmark_list *)cmark_calloc(1, sizeof(*data));
+ data->marker_offset = 0; // will be adjusted later
+ data->list_type = CMARK_BULLET_LIST;
+ data->bullet_char = c;
+ data->start = 1;
+ data->delimiter = CMARK_PERIOD_DELIM;
+ data->tight = false;
} else if (cmark_isdigit(c)) {
int start = 0;
int digits = 0;
@@ -425,21 +419,16 @@ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
if (!cmark_isspace(peek_at(input, pos))) {
return 0;
}
- data = (cmark_list *)calloc(1, sizeof(*data));
- if (data == NULL) {
- return 0;
- } else {
- data->marker_offset = 0; // will be adjusted later
- data->list_type = CMARK_ORDERED_LIST;
- data->bullet_char = 0;
- data->start = start;
- data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
- data->tight = false;
- }
+ data = (cmark_list *)cmark_calloc(1, sizeof(*data));
+ data->marker_offset = 0; // will be adjusted later
+ data->list_type = CMARK_ORDERED_LIST;
+ data->bullet_char = 0;
+ data->start = start;
+ data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
+ data->tight = false;
} else {
return 0;
}
-
} else {
return 0;
}
diff --git a/src/buffer.c b/src/buffer.c
index 80ca49a..2ac3b04 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -10,6 +10,7 @@
#include "config.h"
#include "cmark_ctype.h"
#include "buffer.h"
+#include "memory.h"
/* Used as default value for cmark_strbuf->ptr so that people can always
* assume ptr is non-NULL and zero terminated even for new cmark_strbufs.
@@ -29,34 +30,18 @@ void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size) {
cmark_strbuf_grow(buf, initial_size);
}
-static CMARK_INLINE bool S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
- return cmark_strbuf_grow(buf, buf->size + add);
+static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
+ cmark_strbuf_grow(buf, buf->size + add);
}
-#if BUFSIZE_MAX > (SIZE_MAX / 4)
-# error "unsafe value for BUFSIZE_MAX"
-#endif
-
-bool cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
+void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
assert(target_size > 0);
if (target_size < buf->asize)
- return true;
-
- /*
- * Do not allow string buffers to grow past this "safe" value.
- *
- * Note that this is a soft cap to prevent unbounded memory growth:
- * in practice, the buffer can get larger than this value because we
- * overgrow it by 50%
- *
- * Note that there are no overflow checks for the realloc because
- * the value of BUFSIZE_MAX is always assured to be impossible
- * to overflow on both 32 and 64 bit systems, since it will never
- * be larger than 1/4th of our address space.
- */
- if (target_size > BUFSIZE_MAX)
- return false;
+ return;
+
+ if (target_size > (bufsize_t)(SIZE_MAX / 4))
+ cmark_trigger_oom();
/* Oversize the buffer by 50% to guarantee amortized linear time
* complexity on append operations. */
@@ -64,13 +49,10 @@ bool cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
new_size += 1;
new_size = (new_size + 7) & ~7;
- unsigned char *new_ptr = realloc(buf->asize ? buf->ptr : NULL, new_size);
- if (!new_ptr)
- return false;
+ unsigned char *new_ptr = cmark_realloc(buf->asize ? buf->ptr : NULL, new_size);
buf->asize = new_size;
buf->ptr = new_ptr;
- return true;
}
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; }
@@ -98,8 +80,8 @@ void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
cmark_strbuf_clear(buf);
} else {
if (data != buf->ptr) {
- if (len >= buf->asize && !cmark_strbuf_grow(buf, len))
- return;
+ if (len >= buf->asize)
+ cmark_strbuf_grow(buf, len);
memmove(buf->ptr, data, len);
}
buf->size = len;
@@ -113,17 +95,17 @@ void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) {
}
void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
- if (!S_strbuf_grow_by(buf, 1))
- return;
+ S_strbuf_grow_by(buf, 1);
buf->ptr[buf->size++] = (unsigned char)(c & 0xFF);
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len) {
- if (len <= 0 || !S_strbuf_grow_by(buf, len))
+ if (len <= 0)
return;
+ S_strbuf_grow_by(buf, len);
memmove(buf->ptr + buf->size, data, len);
buf->size += len;
buf->ptr[buf->size] = '\0';
@@ -165,7 +147,7 @@ unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
if (buf->asize == 0) {
/* return an empty string */
- return (unsigned char *)calloc(1, 1);
+ return cmark_calloc(1, 1);
}
cmark_strbuf_init(buf, 0);
diff --git a/src/buffer.h b/src/buffer.h
index ad4f341..93ffc95 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -25,22 +25,6 @@ extern unsigned char cmark_strbuf__initbuf[];
#define GH_BUF_INIT \
{ cmark_strbuf__initbuf, 0, 0 }
-/*
- * Maximum size for memory storage on any given `cmark_strbuf` object.
- *
- * This is a "safe" value to prevent unbounded memory growth when
- * parsing arbitrarily large (and potentially malicious) documents.
- *
- * It is currently set to 32mb, which is a reasonable default for
- * production applications. If you need to parse documents larger than
- * that, you can increase this value up to `SSIZE_MAX / 2` (which in
- * practice resolves to 1/4th of the total address space for the program).
- *
- * Anything larger than that is a security threat and hence static checks
- * will prevent CMark from compiling.
- */
-#define BUFSIZE_MAX (32 * 1024 * 1024)
-
/**
* Initialize a cmark_strbuf structure.
*
@@ -52,7 +36,7 @@ void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size);
/**
* Grow the buffer to hold at least `target_size` bytes.
*/
-bool cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
+void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
void cmark_strbuf_free(cmark_strbuf *buf);
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b);
diff --git a/src/chunk.h b/src/chunk.h
index 234a4f3..acceaa1 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -4,6 +4,7 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
+#include "memory.h"
#include "cmark_ctype.h"
#include "buffer.h"
@@ -61,13 +62,11 @@ static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_chunk *c) {
if (c->alloc) {
return (char *)c->data;
}
- str = (unsigned char *)malloc(c->len + 1);
- if (str != NULL) {
- if (c->len > 0) {
- memcpy(str, c->data, c->len);
- }
- str[c->len] = 0;
+ str = (unsigned char *)cmark_calloc(c->len + 1, 1);
+ if (c->len > 0) {
+ memcpy(str, c->data, c->len);
}
+ str[c->len] = 0;
c->data = str;
c->alloc = 1;
@@ -84,7 +83,7 @@ static CMARK_INLINE void cmark_chunk_set_cstr(cmark_chunk *c, const char *str) {
c->alloc = 0;
} else {
c->len = strlen(str);
- c->data = (unsigned char *)malloc(c->len + 1);
+ c->data = (unsigned char *)cmark_calloc(c->len + 1, 1);
c->alloc = 1;
memcpy(c->data, str, c->len + 1);
}
diff --git a/src/cmark.c b/src/cmark.c
index 3491199..3288308 100644
--- a/src/cmark.c
+++ b/src/cmark.c
@@ -10,6 +10,36 @@ int cmark_version() { return CMARK_VERSION; }
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
+void (*_cmark_on_oom)(void) = NULL;
+
+void cmark_trigger_oom(void)
+{
+ if (_cmark_on_oom)
+ _cmark_on_oom();
+ abort();
+}
+
+void cmark_set_oom_handler(void (*handler)(void))
+{
+ _cmark_on_oom = handler;
+}
+
+void *cmark_calloc(size_t nmem, size_t size)
+{
+ void *ptr = calloc(nmem, size);
+ if (!ptr)
+ cmark_trigger_oom();
+ return ptr;
+}
+
+void *cmark_realloc(void *ptr, size_t size)
+{
+ void *ptr_new = realloc(ptr, size);
+ if (!ptr_new)
+ cmark_trigger_oom();
+ return ptr_new;
+}
+
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
cmark_node *doc;
char *result;
diff --git a/src/cmark.h b/src/cmark.h
index 911ceb7..a43011b 100644
--- a/src/cmark.h
+++ b/src/cmark.h
@@ -573,6 +573,20 @@ int cmark_version();
CMARK_EXPORT
const char *cmark_version_string();
+/** Set the callback function that will be issued whenever the
+ * library hits an out of memory situation.
+ *
+ * This can happen when the heap memory allocator fails to allocate
+ * a block of memory, or when the index of an in-memory buffer overflows
+ *
+ * If no OOM handler is set, the library will call `abort` and
+ * terminate itself and the running process. If the custom OOM handler
+ * you set does return (i.e. it does not gracefully terminate the
+ * application), the behavior of the library will be unspecified.
+ */
+CMARK_EXPORT
+void cmark_set_oom_handler(void (*handler)(void));
+
/** # AUTHORS
*
* John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
diff --git a/src/inlines.c b/src/inlines.c
index 6acbb44..f2e7cf1 100644
--- a/src/inlines.c
+++ b/src/inlines.c
@@ -63,38 +63,16 @@ static bufsize_t subject_find_special_char(subject *subj, int options);
// Create an inline with a literal string value.
static CMARK_INLINE cmark_node *make_literal(cmark_node_type t, cmark_chunk s) {
- cmark_node *e = (cmark_node *)calloc(1, sizeof(*e));
- if (e != NULL) {
- e->type = t;
- e->as.literal = s;
- e->next = NULL;
- e->prev = NULL;
- e->parent = NULL;
- e->first_child = NULL;
- e->last_child = NULL;
- // These fields aren't used for inlines:
- e->start_line = 0;
- e->start_column = 0;
- e->end_line = 0;
- }
+ cmark_node *e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+ e->type = t;
+ e->as.literal = s;
return e;
}
// Create an inline with no value.
static CMARK_INLINE cmark_node *make_simple(cmark_node_type t) {
- cmark_node *e = (cmark_node *)calloc(1, sizeof(*e));
- if (e != NULL) {
- e->type = t;
- e->next = NULL;
- e->prev = NULL;
- e->parent = NULL;
- e->first_child = NULL;
- e->last_child = NULL;
- // These fields aren't used for inlines:
- e->start_line = 0;
- e->start_column = 0;
- e->end_line = 0;
- }
+ cmark_node *e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+ e->type = t;
return e;
}
@@ -116,7 +94,7 @@ static cmark_chunk chunk_clone(cmark_chunk *src) {
bufsize_t len = src->len;
c.len = len;
- c.data = (unsigned char *)malloc(len + 1);
+ c.data = (unsigned char *)cmark_calloc(len + 1, 1);
c.alloc = 1;
memcpy(c.data, src->data, len);
c.data[len] = '\0';
@@ -362,10 +340,7 @@ static void remove_delimiter(subject *subj, delimiter *delim) {
static void push_delimiter(subject *subj, unsigned char c, bool can_open,
bool can_close, cmark_node *inl_text) {
- delimiter *delim = (delimiter *)malloc(sizeof(delimiter));
- if (delim == NULL) {
- return;
- }
+ delimiter *delim = (delimiter *)cmark_calloc(1, sizeof(delimiter));
delim->delim_char = c;
delim->can_open = can_open;
delim->can_close = can_close;
diff --git a/src/iterator.c b/src/iterator.c
index 351b81f..40287f5 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -16,10 +16,7 @@ cmark_iter *cmark_iter_new(cmark_node *root) {
if (root == NULL) {
return NULL;
}
- cmark_iter *iter = (cmark_iter *)malloc(sizeof(cmark_iter));
- if (iter == NULL) {
- return NULL;
- }
+ cmark_iter *iter = (cmark_iter *)cmark_calloc(1, sizeof(cmark_iter));
iter->root = root;
iter->cur.ev_type = CMARK_EVENT_NONE;
iter->cur.node = NULL;
diff --git a/src/main.c b/src/main.c
index ff752e5..5ea4b61 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <errno.h>
#include "config.h"
+#include "memory.h"
#include "cmark.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -80,7 +81,7 @@ int main(int argc, char *argv[]) {
_setmode(_fileno(stdout), _O_BINARY);
#endif
- files = (int *)malloc(argc * sizeof(*files));
+ files = (int *)cmark_calloc(argc, sizeof(*files));
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0) {
diff --git a/src/memory.h b/src/memory.h
new file mode 100644
index 0000000..f05d566
--- /dev/null
+++ b/src/memory.h
@@ -0,0 +1,12 @@
+#ifndef CMARK_MEM_H
+#define CMARK_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *cmark_calloc(size_t nmem, size_t size);
+void *cmark_realloc(void *ptr, size_t size);
+void cmark_trigger_oom(void);
+
+#endif
diff --git a/src/node.c b/src/node.c
index 00edbb1..30cd69f 100644
--- a/src/node.c
+++ b/src/node.c
@@ -71,7 +71,7 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
}
cmark_node *cmark_node_new(cmark_node_type type) {
- cmark_node *node = (cmark_node *)calloc(1, sizeof(*node));
+ cmark_node *node = (cmark_node *)cmark_calloc(1, sizeof(*node));
node->type = type;
switch (node->type) {
diff --git a/src/references.c b/src/references.c
index 6cb2b20..168bd89 100755
--- a/src/references.c
+++ b/src/references.c
@@ -76,16 +76,14 @@ void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
if (reflabel == NULL)
return;
- ref = (cmark_reference *)calloc(1, sizeof(*ref));
- if (ref != NULL) {
- ref->label = reflabel;
- ref->hash = refhash(ref->label);
- ref->url = cmark_clean_url(url);
- ref->title = cmark_clean_title(title);
- ref->next = NULL;
-
- add_reference(map, ref);
- }
+ ref = (cmark_reference *)cmark_calloc(1, sizeof(*ref));
+ ref->label = reflabel;
+ ref->hash = refhash(ref->label);
+ ref->url = cmark_clean_url(url);
+ ref->title = cmark_clean_title(title);
+ ref->next = NULL;
+
+ add_reference(map, ref);
}
// Returns reference if refmap contains a reference with matching
@@ -140,5 +138,5 @@ void cmark_reference_map_free(cmark_reference_map *map) {
}
cmark_reference_map *cmark_reference_map_new(void) {
- return (cmark_reference_map *)calloc(1, sizeof(cmark_reference_map));
+ return (cmark_reference_map *)cmark_calloc(1, sizeof(cmark_reference_map));
}