summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2015-01-15 12:38:04 (GMT)
committer Vincent Sanders <vince@kyllikki.org>2015-01-15 12:38:04 (GMT)
commitb314f3b54da7892d9f6994ba99082b92b76cf316 (patch)
tree693146aba74da43d511eedb465f1cf60f9c8933c
parent7ec0aa7b69d32f2a545636f7dfbe31641d97d1fa (diff)
downloadlibsvgtiny-b314f3b54da7892d9f6994ba99082b92b76cf316.tar.gz
libsvgtiny-b314f3b54da7892d9f6994ba99082b92b76cf316.tar.bz2
Ensure path generation does not overrun allocated storage.
This fixes bug #2251 which was caused by the svg: <svg width="11" height="11" id="support-entry-icon" y="3389"><g><g><path fill-rule="evenodd" clip-rule="evenodd" fill="#D6D6D6" d="M0,0v11h11V0H0z M10,10H1V1h9V10z M9,3H2v1h7V3z M9,5H2v1h7V5z M9,7H2v1h7V7z"/></g></g></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.
-rw-r--r--src/svgtiny.c56
1 files changed, 50 insertions, 6 deletions
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);