aboutsummaryrefslogtreecommitdiff
path: root/stdlib/setenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/setenv.c')
-rw-r--r--stdlib/setenv.c66
1 files changed, 33 insertions, 33 deletions
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
index c6dc9f7945..2a2eec9c98 100644
--- a/stdlib/setenv.c
+++ b/stdlib/setenv.c
@@ -191,52 +191,52 @@ __add_to_environ (const char *name, const char *value, const char *combined,
ep[1] = NULL;
else
{
- /* We cannot use __environ as is and need a larger allocation. */
-
- if (start_environ == __environ_startup
- || __environ_is_from_array_list (start_environ))
- {
- /* Allocate a new array, managed in the list. */
- struct environ_array *target_array
- = __environ_new_array (required_size);
- if (target_array == NULL)
- {
- UNLOCK;
- return -1;
- }
- result_environ = &target_array->array[0];
-
- /* Copy over the __environ array contents. This code
- handles the case start_environ == ep == NULL, too. */
- size_t i;
- for (i = 0; start_environ + i < ep; ++i)
- /* Regular store because unless there has been direct
- manipulation of the environment, target_array is still
- a private copy. */
- result_environ[i] = atomic_load_relaxed (start_environ + i);
- }
+ /* We cannot use __environ as is and need to copy over the
+ __environ contents into an array managed via
+ __environ_array_list. */
+
+ struct environ_array *target_array;
+ if (__environ_array_list != NULL
+ && required_size <= __environ_array_list->allocated)
+ /* Existing array has enough room. Contents is copied below. */
+ target_array = __environ_array_list;
else
{
- /* Otherwise the application installed its own pointer.
- Historically, this pointer was managed using realloc.
- Continue doing so. This disables multi-threading
- support. */
- result_environ = __libc_reallocarray (start_environ,
- required_size,
- sizeof (*result_environ));
- if (result_environ == NULL)
+ /* Allocate a new array. */
+ target_array = __environ_new_array (required_size);
+ if (target_array == NULL)
{
UNLOCK;
return -1;
}
}
+ /* Copy over the __environ array contents. This forward
+ copy slides backwards part of the array if __environ
+ points into target_array->array. This happens if an
+ application makes an assignment like:
+
+ environ = &environ[1];
+
+ The forward copy avoids clobbering values that still
+ needing copying. This code handles the case
+ start_environ == ep == NULL, too. */
+ size_t i;
+ for (i = 0; start_environ + i < ep; ++i)
+ /* Regular store because unless there has been direct
+ manipulation of the environment, target_array is still
+ a private copy. */
+ target_array->array[i] = atomic_load_relaxed (start_environ + i);
+
/* This is the new place where we should add the element. */
- ep = result_environ + (required_size - 2);
+ ep = target_array->array + i;
/* Add the null terminator in case there was a pointer there
previously. */
ep[1] = NULL;
+
+ /* And __environ should be repointed to our array. */
+ result_environ = &target_array->array[0];
}
}