diff options
author | Stefan Bühler <stbuehler@web.de> | 2016-03-15 18:26:57 +0000 |
---|---|---|
committer | Stefan Bühler <stbuehler@web.de> | 2016-03-15 18:26:57 +0000 |
commit | 8d8ae9cbc8b7d8394d28d472a439d3ef282d808f (patch) | |
tree | 5e9fd2d4e5bdd015d6c1cfcf8904f3aea45f1cf0 /src/configparser.y | |
parent | c5a42e932f948cdb2d76a8c79bfaebd6c8cf6376 (diff) | |
download | lighttpd-git-8d8ae9cbc8b7d8394d28d472a439d3ef282d808f.tar.gz |
[core] improve array API to prevent theoretical memory leaks
- refactor insert into array_find_or_insert; if the element already
exists the caller must resolve the conflict manually:
- array_replace frees the old element
- array_insert_unique calls "insert_dup"
both have no return value anymore
- fix usages of array_replace; they now don't need to delete the old
entry anymore; usage in configparser was probably broken, as it
possibly deleted the old element before calling array_replace
This should fix a lot of the issues reported in "Fortify Open Review
Project - lighttpd 1.4.39" (usually hitting the array limit):
when the array size limit was hit "new" entries leaked instead of
getting added.
On 32-bit INT_MAX entries cannot actually be reached (each entry
requires at least 48 bytes, leading to a total of 96GB memory).
On 64-bit INT_MAX entries would require 224GB memory, so it would be
theoretically possible. But it would need 2^27 reallocations of two
C-arrays of up to 16GB size.
From: Stefan Bühler <stbuehler@web.de>
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@3098 152afb58-edef-0310-8abb-c4023f1b3aa9
Diffstat (limited to 'src/configparser.y')
-rw-r--r-- | src/configparser.y | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/src/configparser.y b/src/configparser.y index 666d59be..10241456 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -178,14 +178,23 @@ varline ::= key(A) APPEND expression(B). { ctx->ok = 0; } else if (NULL != (du = array_get_element(vars, A->ptr))) { /* exists in current block */ - du = configparser_merge_data(du, B); + if (du->type != B->type) { + /* might create new data when merging different types; need to replace old array entry */ + /* also merging will kill the old data */ + du = du->copy(du); + du = configparser_merge_data(du, B); + if (NULL != du) { + buffer_copy_buffer(du->key, A); + array_replace(vars, du); + } + } else { + data_unset *old_du = du; + du = configparser_merge_data(old_du, B); + force_assert((NULL == du) || (du == old_du)); /* must not create new data when types match */ + } if (NULL == du) { ctx->ok = 0; } - else { - buffer_copy_buffer(du->key, A); - array_replace(vars, du); - } B->free(B); } else if (NULL != (du = configparser_get_variable(ctx, A))) { du = configparser_merge_data(du, B); |