-/* Copyright (C) 1992-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
+ <https://www.gnu.org/licenses/>. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
+/* Pacify GCC; see the commentary about VALLEN below. This is needed
+ at least through GCC 4.9.2. Pacify GCC for the entire file, as
+ there seems to be no way to pacify GCC selectively, only for the
+ place where it's needed. Do not use DIAG_IGNORE_NEEDS_COMMENT
+ here, as it's not defined yet. */
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+
#include <errno.h>
#if !_LIBC
# if !defined errno && !defined HAVE_ERRNO_DECL
#if _LIBC
/* This lock protects against simultaneous modifications of `environ'. */
-# include <bits/libc-lock.h>
+# include <libc-lock.h>
__libc_lock_define_initialized (static, envlock)
# define LOCK __libc_lock_lock (envlock)
# define UNLOCK __libc_lock_unlock (envlock)
to reuse values once generated for a `setenv' call since we can never
free the strings. */
int
-__add_to_environ (name, value, combined, replace)
- const char *name;
- const char *value;
- const char *combined;
- int replace;
+__add_to_environ (const char *name, const char *value, const char *combined,
+ int replace)
{
char **ep;
size_t size;
+
+ /* Compute lengths before locking, so that the critical section is
+ less of a performance bottleneck. VALLEN is needed only if
+ COMBINED is null (unfortunately GCC is not smart enough to deduce
+ this; see the #pragma at the start of this file). Testing
+ COMBINED instead of VALUE causes setenv (..., NULL, ...) to dump
+ core now instead of corrupting memory later. */
const size_t namelen = strlen (name);
- const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
+ size_t vallen;
+ if (combined == NULL)
+ vallen = strlen (value) + 1;
LOCK;
{
char **new_environ;
- /* We allocated this space; we can extend it. */
+ /* We allocated this space; we can extend it. Avoid using the raw
+ reallocated pointer to avoid GCC -Wuse-after-free. */
+ uintptr_t ip_last_environ = (uintptr_t)last_environ;
new_environ = (char **) realloc (last_environ,
(size + 2) * sizeof (char *));
if (new_environ == NULL)
return -1;
}
- if (__environ != last_environ)
+ if ((uintptr_t)__environ != ip_last_environ)
memcpy ((char *) new_environ, (char *) __environ,
size * sizeof (char *));
}
int
-setenv (name, value, replace)
- const char *name;
- const char *value;
- int replace;
+setenv (const char *name, const char *value, int replace)
{
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
}
int
-unsetenv (name)
- const char *name;
+unsetenv (const char *name)
{
size_t len;
char **ep;
ep = __environ;
if (ep != NULL)
while (*ep != NULL)
- if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
- {
- /* Found it. Remove this pointer by moving later ones back. */
- char **dp = ep;
-
- do
- dp[0] = dp[1];
- while (*dp++);
- /* Continue the loop in case NAME appears again. */
- }
- else
- ++ep;
+ {
+ if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones back. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+ }
UNLOCK;
return 0;
}
#ifdef _LIBC
-libc_freeres_fn (free_mem)
+void
+__libc_setenv_freemem (void)
{
/* Remove all traces. */
clearenv ();