summaryrefslogtreecommitdiff
path: root/src/configparser.y
diff options
context:
space:
mode:
authorStefan Bühler <stbuehler@web.de>2016-03-15 18:26:57 +0000
committerStefan Bühler <stbuehler@web.de>2016-03-15 18:26:57 +0000
commit8d8ae9cbc8b7d8394d28d472a439d3ef282d808f (patch)
tree5e9fd2d4e5bdd015d6c1cfcf8904f3aea45f1cf0 /src/configparser.y
parentc5a42e932f948cdb2d76a8c79bfaebd6c8cf6376 (diff)
downloadlighttpd-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.y19
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);