summaryrefslogtreecommitdiff
path: root/libc/unistd/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/unistd/exec.c')
-rw-r--r--libc/unistd/exec.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/libc/unistd/exec.c b/libc/unistd/exec.c
index b91ce0c98..381a81464 100644
--- a/libc/unistd/exec.c
+++ b/libc/unistd/exec.c
@@ -56,7 +56,9 @@ libc_hidden_proto(getenv)
/* We do not have an MMU, so using alloca() is not an option.
* Less obviously, using malloc() is not an option either since
* malloc()ed memory can leak in a vfork() and exec*() situation.
- * Therefore, we must use mmap() and unmap() directly.
+ * Therefore, we must use mmap() and unmap() directly, caching
+ * the result as we go. This way we minimize the leak to 1
+ * allocation.
*/
# define EXEC_ALLOC_SIZE(VAR) size_t VAR; /* Semicolon included! */
@@ -68,22 +70,28 @@ extern void __exec_free(void *ptr, size_t size) attribute_hidden;
# ifdef L___exec_alloc
+void attribute_hidden __exec_free(void *ptr, size_t size)
+{
+ if (ptr)
+ munmap(ptr, size);
+}
+
void attribute_hidden *__exec_alloc(size_t size)
{
- void *p;
+ static void *p;
+ static size_t old_size;
+
+ if (old_size >= size)
+ return p;
+ else
+ __exec_free(p, old_size);
+ old_size = size;
p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
return (p != MAP_FAILED) ? p : NULL;
}
-void attribute_hidden __exec_free(void *ptr, size_t size)
-{
- if (ptr) {
- munmap(ptr, size);
- }
-}
-
# endif
#endif