From b314f3b54da7892d9f6994ba99082b92b76cf316 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 15 Jan 2015 12:38:04 +0000 Subject: Ensure path generation does not overrun allocated storage. This fixes bug #2251 which was caused by the svg: The svg was causing more path elements to be generated in the internal representation than space was allocated for and overrunning heap blocks. The path element parsing was using a fixed size allocation for the path elements and never bounds checked. Further it did not cope with zero length paths (which the spec says are permitted). It was also grossly overallocating for the common case. This changes the path element array to be bounds checked and then extended if required, the initial allocation is generally sufficient and in testing very few resizes occurred. The reallocation strategy grows the element storage by 2.5 each time this means even in the degenerate case very few reallocations are required. In testing no more than a single reallocation has been observed. The final path element array will always be reallocted to the minimum required size. This reduces overall memory usage which is useful with complex scenes. --- src/svgtiny.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/svgtiny.c b/src/svgtiny.c index f02f3d6..6215b04 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -402,7 +402,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, dom_string *path_d_str; dom_exception exc; char *s, *path_d; - float *p; + float *p; /* path elemets */ + unsigned int palloc; /* number of path elements allocated */ unsigned int i; float last_x = 0, last_y = 0; float last_cubic_x = 0, last_cubic_y = 0; @@ -430,16 +431,31 @@ svgtiny_code svgtiny_parse_path(dom_element *path, return svgtiny_SVG_ERROR; } - s = path_d = strndup(dom_string_data(path_d_str), - dom_string_byte_length(path_d_str)); + /* empty path is permitted it just disables the path */ + palloc = dom_string_byte_length(path_d_str); + if (palloc == 0) { + svgtiny_cleanup_state_local(&state); + return svgtiny_OK; + } + + /* local copy of the path data allowing in-place modification */ + s = path_d = strndup(dom_string_data(path_d_str), palloc); dom_string_unref(path_d_str); if (s == NULL) { svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } - /* allocate space for path: it will never have more elements than d */ - p = malloc(sizeof p[0] * strlen(s)); - if (!p) { + + /* ensure path element allocation is sensibly bounded */ + if (palloc < 8) { + palloc = 8; + } else if (palloc > 64) { + palloc = palloc / 2; + } + + /* allocate initial space for path elements */ + p = malloc(sizeof p[0] * palloc); + if (p == NULL) { free(path_d); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; @@ -456,6 +472,21 @@ svgtiny_code svgtiny_parse_path(dom_element *path, float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep; int n; + /* Ensure there is sufficient space for path elements */ + if ((palloc - i) < 7) { + float *tp; + palloc = (palloc * 2) + (palloc / 2); + tp = realloc(p, sizeof p[0] * palloc); + if (tp == NULL) { + free(p); + free(path_d); + svgtiny_cleanup_state_local(&state); + return svgtiny_OUT_OF_MEMORY; + } + p = tp; + } + + /* moveto (M, m), lineto (L, l) (2 arguments) */ if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("moveto or lineto"));*/ @@ -648,6 +679,19 @@ svgtiny_code svgtiny_parse_path(dom_element *path, return svgtiny_OK; } + /* resize path element array to not be over allocated */ + if (palloc != i) { + float *tp; + + /* try the resize, if it fails just continue to use the old + * allocation + */ + tp = realloc(p, sizeof p[0] * i); + if (tp != NULL) { + p = tp; + } + } + err = svgtiny_add_path(p, i, &state); svgtiny_cleanup_state_local(&state); -- cgit v1.2.3