[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] /srv/bzr/emacs/trunk r111158: Use putenv+unsetenv instead
From: |
Paul Eggert |
Subject: |
[Emacs-diffs] /srv/bzr/emacs/trunk r111158: Use putenv+unsetenv instead of modifying environ directly. |
Date: |
Sat, 08 Dec 2012 09:19:51 -0800 |
User-agent: |
Bazaar (2.5.0) |
------------------------------------------------------------
revno: 111158
fixes bug: http://debbugs.gnu.org/13070
committer: Paul Eggert <address@hidden>
branch nick: trunk
timestamp: Sat 2012-12-08 09:19:51 -0800
message:
Use putenv+unsetenv instead of modifying environ directly.
* admin/merge-gnulib (GNULIB_MODULES): Add putenv, unsetenv.
* lib/putenv.c, lib/unsetenv.c, m4/putenv.m4, m4/setenv.m4:
New files, copied automatically from gnulib.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* src/alloc.c (xputenv): New function.
* src/dbusbind.c (Fdbus_init_bus):
* src/emacs.c (main):
* src/xterm.c (x_term_init):
Use xputenv instead of setenv or putenv, to detect memory exhaustion.
* src/editfns.c (initial_tz): Move static var decl up.
(tzvalbuf_in_environ): New static var.
(init_editfns): Initialize these two static vars.
(Fencode_time): Don't assume arbitrary limit on EMACS_INT width.
Save old TZ value on stack, if it's small.
(Fencode_time, set_time_zone_rule): Don't modify 'environ' directly;
instead, use xputenv+unsetenv to set and restore TZ.
(environbuf): Remove static var. All uses removed.
(Fset_time_zone_rule): Do not save TZ and environ;
no longer needed here.
(set_time_zone_rule_tz1, set_time_zone_rule_tz2) [LOCALTIME_CACHE]:
Move to inside set_time_zone_rule; they don't need file scope any more.
(set_time_zone_rule): Maintain the TZ=value string separately.
(syms_of_editfns): Don't initialize initial_tz;
init_editfns now does it.
* src/emacs.c (dump_tz) [HAVE_TZSET]: Now const.
* src/lisp.h (xputenv): New decl.
added:
lib/putenv.c
lib/unsetenv.c
m4/putenv.m4
m4/setenv.m4
modified:
ChangeLog
admin/ChangeLog
admin/merge-gnulib
lib/gnulib.mk
m4/gnulib-comp.m4
src/ChangeLog
src/alloc.c
src/dbusbind.c
src/editfns.c
src/emacs.c
src/lisp.h
src/xterm.c
=== modified file 'ChangeLog'
--- a/ChangeLog 2012-12-08 09:57:43 +0000
+++ b/ChangeLog 2012-12-08 17:19:51 +0000
@@ -1,3 +1,10 @@
+2012-12-08 Paul Eggert <address@hidden>
+
+ Use putenv+unsetenv instead of modifying environ directly (Bug#13070).
+ * lib/putenv.c, lib/unsetenv.c, m4/putenv.m4, m4/setenv.m4:
+ New files, copied automatically from gnulib.
+ * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
2012-12-08 Eli Zaretskii <address@hidden>
* lib/makefile.w32-in ($(BLD)/sig2str.$(O)): New dependency.
=== modified file 'admin/ChangeLog'
--- a/admin/ChangeLog 2012-12-08 06:56:26 +0000
+++ b/admin/ChangeLog 2012-12-08 17:19:51 +0000
@@ -1,5 +1,8 @@
2012-12-08 Paul Eggert <address@hidden>
+ Use putenv+unsetenv instead of modifying environ directly (Bug#13070).
+ * merge-gnulib (GNULIB_MODULES): Add putenv, unsetenv.
+
Simplify get_lim_data.
* CPP-DEFINES (ULIMIT_BREAK_VALUE): Remove.
=== modified file 'admin/merge-gnulib'
--- a/admin/merge-gnulib 2012-12-08 02:30:51 +0000
+++ b/admin/merge-gnulib 2012-12-08 17:19:51 +0000
@@ -31,10 +31,10 @@
dtoastr dtotimespec dup2 environ execinfo faccessat
fcntl-h filemode getloadavg getopt-gnu gettime gettimeofday
ignore-value intprops largefile lstat
- manywarnings mktime pselect pthread_sigmask readlink
+ manywarnings mktime pselect pthread_sigmask putenv readlink
sig2str socklen stat-time stdalign stdarg stdbool stdio
strftime strtoimax strtoumax symlink sys_stat
- sys_time time timer-time timespec-add timespec-sub utimens
+ sys_time time timer-time timespec-add timespec-sub unsetenv utimens
warnings
'
=== modified file 'lib/gnulib.mk'
--- a/lib/gnulib.mk 2012-12-08 02:30:51 +0000
+++ b/lib/gnulib.mk 2012-12-08 17:19:51 +0000
@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux
--avoid=at-internal --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die
--avoid=openat-h --avoid=raise --avoid=save-cwd --avoid=select
--avoid=sigprocmask --avoid=sys_types --avoid=threadlib
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr
dtotimespec dup2 environ execinfo faccessat fcntl-h filemode getloadavg
getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat
manywarnings mktime pselect pthread_sigmask readlink sig2str socklen stat-time
stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat
sys_time time timer-time timespec-add timespec-sub utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux
--avoid=at-internal --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die
--avoid=openat-h --avoid=raise --avoid=save-cwd --avoid=select
--avoid=sigprocmask --avoid=sys_types --avoid=threadlib
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr
dtotimespec dup2 environ execinfo faccessat fcntl-h filemode getloadavg
getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat
manywarnings mktime pselect pthread_sigmask putenv readlink sig2str socklen
stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink
sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens
warnings
MOSTLYCLEANFILES += core *.stackdump
@@ -439,6 +439,15 @@
## end gnulib module pthread_sigmask
+## begin gnulib module putenv
+
+
+EXTRA_DIST += putenv.c
+
+EXTRA_libgnu_a_SOURCES += putenv.c
+
+## end gnulib module putenv
+
## begin gnulib module readlink
@@ -1409,6 +1418,15 @@
## end gnulib module unistd
+## begin gnulib module unsetenv
+
+
+EXTRA_DIST += unsetenv.c
+
+EXTRA_libgnu_a_SOURCES += unsetenv.c
+
+## end gnulib module unsetenv
+
## begin gnulib module utimens
libgnu_a_SOURCES += utimens.c
=== added file 'lib/putenv.c'
--- a/lib/putenv.c 1970-01-01 00:00:00 +0000
+++ b/lib/putenv.c 2012-12-08 17:19:51 +0000
@@ -0,0 +1,134 @@
+/* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2012 Free Software
+ Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to address@hidden
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <stdlib.h>
+
+#include <stddef.h>
+
+/* Include errno.h *after* sys/types.h to work around header problems
+ on AIX 3.2.5. */
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <string.h>
+#include <unistd.h>
+
+#if _LIBC
+# if HAVE_GNU_LD
+# define environ __environ
+# else
+extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of 'environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+static int
+_unsetenv (const char *name)
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ len = strlen (name);
+
+ LOCK;
+
+ ep = environ;
+ 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;
+
+ UNLOCK;
+
+ return 0;
+}
+
+
+/* Put STRING, which is of the form "NAME=VALUE", in the environment.
+ If STRING contains no '=', then remove STRING from the environment. */
+int
+putenv (char *string)
+{
+ const char *const name_end = strchr (string, '=');
+ register size_t size;
+ register char **ep;
+
+ if (name_end == NULL)
+ {
+ /* Remove the variable from the environment. */
+ return _unsetenv (string);
+ }
+
+ size = 0;
+ for (ep = environ; *ep != NULL; ++ep)
+ if (!strncmp (*ep, string, name_end - string) &&
+ (*ep)[name_end - string] == '=')
+ break;
+ else
+ ++size;
+
+ if (*ep == NULL)
+ {
+ static char **last_environ = NULL;
+ char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
+ if (new_environ == NULL)
+ return -1;
+ (void) memcpy ((void *) new_environ, (void *) environ,
+ size * sizeof (char *));
+ new_environ[size] = (char *) string;
+ new_environ[size + 1] = NULL;
+ free (last_environ);
+ last_environ = new_environ;
+ environ = new_environ;
+ }
+ else
+ *ep = string;
+
+ return 0;
+}
=== added file 'lib/unsetenv.c'
--- a/lib/unsetenv.c 1970-01-01 00:00:00 +0000
+++ b/lib/unsetenv.c 2012-12-08 17:19:51 +0000
@@ -0,0 +1,127 @@
+/* Copyright (C) 1992, 1995-2002, 2005-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
+ optimizes away the name == NULL test below. */
+#define _GL_ARG_NONNULL(params)
+
+/* Specification. */
+#include <stdlib.h>
+
+#include <errno.h>
+#if !_LIBC
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <string.h>
+#include <unistd.h>
+
+#if !_LIBC
+# define __environ environ
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of 'environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define unsetenv __unsetenv
+#endif
+
+#if _LIBC || !HAVE_UNSETENV
+
+int
+unsetenv (const char *name)
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ len = strlen (name);
+
+ LOCK;
+
+ ep = __environ;
+ 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;
+
+ UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+# undef unsetenv
+weak_alias (__unsetenv, unsetenv)
+#endif
+
+#else /* HAVE_UNSETENV */
+
+# undef unsetenv
+# if !HAVE_DECL_UNSETENV
+# if VOID_UNSETENV
+extern void unsetenv (const char *);
+# else
+extern int unsetenv (const char *);
+# endif
+# endif
+
+/* Call the underlying unsetenv, in case there is hidden bookkeeping
+ that needs updating beyond just modifying environ. */
+int
+rpl_unsetenv (const char *name)
+{
+ int result = 0;
+ if (!name || !*name || strchr (name, '='))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ while (getenv (name))
+# if !VOID_UNSETENV
+ result =
+# endif
+ unsetenv (name);
+ return result;
+}
+
+#endif /* HAVE_UNSETENV */
=== modified file 'm4/gnulib-comp.m4'
--- a/m4/gnulib-comp.m4 2012-12-08 02:30:51 +0000
+++ b/m4/gnulib-comp.m4 2012-12-08 17:19:51 +0000
@@ -85,6 +85,7 @@
# Code from module pathmax:
# Code from module pselect:
# Code from module pthread_sigmask:
+ # Code from module putenv:
# Code from module readlink:
# Code from module root-uid:
# Code from module sig2str:
@@ -126,6 +127,7 @@
# Code from module timespec-sub:
# Code from module u64:
# Code from module unistd:
+ # Code from module unsetenv:
# Code from module utimens:
# Code from module verify:
# Code from module warnings:
@@ -240,6 +242,11 @@
gl_PREREQ_PTHREAD_SIGMASK
fi
gl_SIGNAL_MODULE_INDICATOR([pthread_sigmask])
+ gl_FUNC_PUTENV
+ if test $REPLACE_PUTENV = 1; then
+ AC_LIBOBJ([putenv])
+ fi
+ gl_STDLIB_MODULE_INDICATOR([putenv])
gl_FUNC_READLINK
if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
AC_LIBOBJ([readlink])
@@ -297,6 +304,12 @@
gl_TIMER_TIME
gl_TIMESPEC
gl_UNISTD_H
+ gl_FUNC_UNSETENV
+ if test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1; then
+ AC_LIBOBJ([unsetenv])
+ gl_PREREQ_UNSETENV
+ fi
+ gl_STDLIB_MODULE_INDICATOR([unsetenv])
gl_UTIMENS
gl_gnulib_enabled_dosname=false
gl_gnulib_enabled_euidaccess=false
@@ -679,6 +692,7 @@
lib/pathmax.h
lib/pselect.c
lib/pthread_sigmask.c
+ lib/putenv.c
lib/readlink.c
lib/root-uid.h
lib/sha1.c
@@ -723,6 +737,7 @@
lib/u64.h
lib/unistd.c
lib/unistd.in.h
+ lib/unsetenv.c
lib/utimens.c
lib/utimens.h
lib/verify.h
@@ -764,7 +779,9 @@
m4/pathmax.m4
m4/pselect.m4
m4/pthread_sigmask.m4
+ m4/putenv.m4
m4/readlink.m4
+ m4/setenv.m4
m4/sha1.m4
m4/sha256.m4
m4/sha512.m4
=== added file 'm4/putenv.m4'
--- a/m4/putenv.m4 1970-01-01 00:00:00 +0000
+++ b/m4/putenv.m4 2012-12-08 17:19:51 +0000
@@ -0,0 +1,50 @@
+# putenv.m4 serial 19
+dnl Copyright (C) 2002-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+dnl
+dnl Check whether putenv ("FOO") removes FOO from the environment.
+dnl The putenv in libc on at least SunOS 4.1.4 does *not* do that.
+
+AC_DEFUN([gl_FUNC_PUTENV],
+[
+ AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ AC_CACHE_CHECK([for putenv compatible with GNU and SVID],
+ [gl_cv_func_svid_putenv],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],[[
+ /* Put it in env. */
+ if (putenv ("CONFTEST_putenv=val"))
+ return 1;
+
+ /* Try to remove it. */
+ if (putenv ("CONFTEST_putenv"))
+ return 2;
+
+ /* Make sure it was deleted. */
+ if (getenv ("CONFTEST_putenv") != 0)
+ return 3;
+
+ return 0;
+ ]])],
+ gl_cv_func_svid_putenv=yes,
+ gl_cv_func_svid_putenv=no,
+ dnl When crosscompiling, assume putenv is broken.
+ [case "$host_os" in
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_svid_putenv="guessing yes" ;;
+ # If we don't know, assume the worst.
+ *) gl_cv_func_svid_putenv="guessing no" ;;
+ esac
+ ])
+ ])
+ case "$gl_cv_func_svid_putenv" in
+ *yes) ;;
+ *)
+ REPLACE_PUTENV=1
+ ;;
+ esac
+])
=== added file 'm4/setenv.m4'
--- a/m4/setenv.m4 1970-01-01 00:00:00 +0000
+++ b/m4/setenv.m4 2012-12-08 17:19:51 +0000
@@ -0,0 +1,160 @@
+# setenv.m4 serial 26
+dnl Copyright (C) 2001-2004, 2006-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_SETENV],
+[
+ AC_REQUIRE([gl_FUNC_SETENV_SEPARATE])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ if test $ac_cv_func_setenv = no; then
+ HAVE_SETENV=0
+ else
+ AC_CACHE_CHECK([whether setenv validates arguments],
+ [gl_cv_func_setenv_works],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <string.h>
+ ]], [[
+ int result = 0;
+ {
+ if (setenv ("", "", 0) != -1)
+ result |= 1;
+ else if (errno != EINVAL)
+ result |= 2;
+ }
+ {
+ if (setenv ("a", "=", 1) != 0)
+ result |= 4;
+ else if (strcmp (getenv ("a"), "=") != 0)
+ result |= 8;
+ }
+ return result;
+ ]])],
+ [gl_cv_func_setenv_works=yes], [gl_cv_func_setenv_works=no],
+ [case "$host_os" in
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_setenv_works="guessing yes" ;;
+ # If we don't know, assume the worst.
+ *) gl_cv_func_setenv_works="guessing no" ;;
+ esac
+ ])])
+ case "$gl_cv_func_setenv_works" in
+ *yes) ;;
+ *)
+ REPLACE_SETENV=1
+ ;;
+ esac
+ fi
+])
+
+# Like gl_FUNC_SETENV, except prepare for separate compilation
+# (no REPLACE_SETENV, no AC_LIBOBJ).
+AC_DEFUN([gl_FUNC_SETENV_SEPARATE],
+[
+ AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+ AC_CHECK_DECLS_ONCE([setenv])
+ if test $ac_cv_have_decl_setenv = no; then
+ HAVE_DECL_SETENV=0
+ fi
+ AC_CHECK_FUNCS_ONCE([setenv])
+ gl_PREREQ_SETENV
+])
+
+AC_DEFUN([gl_FUNC_UNSETENV],
+[
+ AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ AC_CHECK_DECLS_ONCE([unsetenv])
+ if test $ac_cv_have_decl_unsetenv = no; then
+ HAVE_DECL_UNSETENV=0
+ fi
+ AC_CHECK_FUNCS([unsetenv])
+ if test $ac_cv_func_unsetenv = no; then
+ HAVE_UNSETENV=0
+ else
+ HAVE_UNSETENV=1
+ dnl Some BSDs return void, failing to do error checking.
+ AC_CACHE_CHECK([for unsetenv() return type], [gt_cv_func_unsetenv_ret],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+#undef _BSD
+#define _BSD 1 /* unhide unsetenv declaration in OSF/1 5.1 <stdlib.h> */
+#include <stdlib.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+int unsetenv (const char *name);
+ ]],
+ [[]])],
+ [gt_cv_func_unsetenv_ret='int'],
+ [gt_cv_func_unsetenv_ret='void'])])
+ if test $gt_cv_func_unsetenv_ret = 'void'; then
+ AC_DEFINE([VOID_UNSETENV], [1], [Define to 1 if unsetenv returns void
+ instead of int.])
+ REPLACE_UNSETENV=1
+ fi
+
+ dnl Solaris 10 unsetenv does not remove all copies of a name.
+ dnl Haiku alpha 2 unsetenv gets confused by assignment to environ.
+ dnl OpenBSD 4.7 unsetenv("") does not fail.
+ AC_CACHE_CHECK([whether unsetenv obeys POSIX],
+ [gl_cv_func_unsetenv_works],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <errno.h>
+ extern char **environ;
+ ]], [[
+ char entry1[] = "a=1";
+ char entry2[] = "b=2";
+ char *env[] = { entry1, entry2, NULL };
+ if (putenv ((char *) "a=1")) return 1;
+ if (putenv (entry2)) return 2;
+ entry2[0] = 'a';
+ unsetenv ("a");
+ if (getenv ("a")) return 3;
+ if (!unsetenv ("") || errno != EINVAL) return 4;
+ entry2[0] = 'b';
+ environ = env;
+ if (!getenv ("a")) return 5;
+ entry2[0] = 'a';
+ unsetenv ("a");
+ if (getenv ("a")) return 6;
+ ]])],
+ [gl_cv_func_unsetenv_works=yes], [gl_cv_func_unsetenv_works=no],
+ [case "$host_os" in
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_unsetenv_works="guessing yes" ;;
+ # If we don't know, assume the worst.
+ *) gl_cv_func_unsetenv_works="guessing no" ;;
+ esac
+ ])])
+ case "$gl_cv_func_unsetenv_works" in
+ *yes) ;;
+ *)
+ REPLACE_UNSETENV=1
+ ;;
+ esac
+ fi
+])
+
+# Prerequisites of lib/setenv.c.
+AC_DEFUN([gl_PREREQ_SETENV],
+[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_REQUIRE([gl_ENVIRON])
+ AC_CHECK_HEADERS_ONCE([unistd.h])
+ AC_CHECK_HEADERS([search.h])
+ AC_CHECK_FUNCS([tsearch])
+])
+
+# Prerequisites of lib/unsetenv.c.
+AC_DEFUN([gl_PREREQ_UNSETENV],
+[
+ AC_REQUIRE([gl_ENVIRON])
+ AC_CHECK_HEADERS_ONCE([unistd.h])
+])
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog 2012-12-08 12:11:29 +0000
+++ b/src/ChangeLog 2012-12-08 17:19:51 +0000
@@ -1,3 +1,29 @@
+2012-12-08 Paul Eggert <address@hidden>
+
+ Use putenv+unsetenv instead of modifying environ directly (Bug#13070).
+ * alloc.c (xputenv): New function.
+ * dbusbind.c (Fdbus_init_bus):
+ * emacs.c (main):
+ * xterm.c (x_term_init):
+ Use xputenv instead of setenv or putenv, to detect memory exhaustion.
+ * editfns.c (initial_tz): Move static var decl up.
+ (tzvalbuf_in_environ): New static var.
+ (init_editfns): Initialize these two static vars.
+ (Fencode_time): Don't assume arbitrary limit on EMACS_INT width.
+ Save old TZ value on stack, if it's small.
+ (Fencode_time, set_time_zone_rule): Don't modify 'environ' directly;
+ instead, use xputenv+unsetenv to set and restore TZ.
+ (environbuf): Remove static var. All uses removed.
+ (Fset_time_zone_rule): Do not save TZ and environ;
+ no longer needed here.
+ (set_time_zone_rule_tz1, set_time_zone_rule_tz2) [LOCALTIME_CACHE]:
+ Move to inside set_time_zone_rule; they don't need file scope any more.
+ (set_time_zone_rule): Maintain the TZ=value string separately.
+ (syms_of_editfns): Don't initialize initial_tz;
+ init_editfns now does it.
+ * emacs.c (dump_tz) [HAVE_TZSET]: Now const.
+ * lisp.h (xputenv): New decl.
+
2012-12-08 Fabrice Popineau <address@hidden>
* w32fns.c (emacs_abort): Don't do arithmetics on void pointers.
=== modified file 'src/alloc.c'
--- a/src/alloc.c 2012-12-03 08:06:02 +0000
+++ b/src/alloc.c 2012-12-08 17:19:51 +0000
@@ -820,6 +820,15 @@
return p;
}
+/* Like putenv, but (1) use the equivalent of xmalloc and (2) the
+ argument is a const pointer. */
+
+void
+xputenv (char const *string)
+{
+ if (putenv ((char *) string) != 0)
+ memory_full (0);
+}
/* Unwind for SAFE_ALLOCA */
=== modified file 'src/dbusbind.c'
--- a/src/dbusbind.c 2012-10-31 11:45:40 +0000
+++ b/src/dbusbind.c 2012-12-08 17:19:51 +0000
@@ -1203,7 +1203,7 @@
xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
/* We do not want to abort. */
- putenv ((char *) "DBUS_FATAL_WARNINGS=0");
+ xputenv ("DBUS_FATAL_WARNINGS=0");
/* Cleanup. */
dbus_error_free (&derror);
=== modified file 'src/editfns.c'
--- a/src/editfns.c 2012-12-08 11:05:39 +0000
+++ b/src/editfns.c 2012-12-08 17:19:51 +0000
@@ -78,6 +78,15 @@
static Lisp_Object Qboundary;
+/* The startup value of the TZ environment variable so it can be
+ restored if the user calls set-time-zone-rule with a nil
+ argument. If null, the TZ environment variable was unset. */
+static char const *initial_tz;
+
+/* True if the static variable tzvalbuf (defined in
+ set_time_zone_rule) is part of 'environ'. */
+static bool tzvalbuf_in_environ;
+
void
init_editfns (void)
@@ -96,6 +105,9 @@
return;
#endif /* not CANNOT_DUMP */
+ initial_tz = getenv ("TZ");
+ tzvalbuf_in_environ = 0;
+
pw = getpwuid (getuid ());
#ifdef MSDOS
/* We let the real user name default to "root" because that's quite
@@ -1900,9 +1912,11 @@
}
else
{
- char tzbuf[100];
+ static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
+ char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
+ char *old_tzstring;
const char *tzstring;
- char **oldenv = environ, **newenv;
+ USE_SAFE_ALLOCA;
if (EQ (zone, Qt))
tzstring = "UTC0";
@@ -1914,13 +1928,20 @@
EMACS_INT zone_hr = abszone / (60*60);
int zone_min = (abszone/60) % 60;
int zone_sec = abszone % 60;
- sprintf (tzbuf, "XXX%s%"pI"d:%02d:%02d", "-" + (XINT (zone) < 0),
+ sprintf (tzbuf, tzbuf_format, "-" + (XINT (zone) < 0),
zone_hr, zone_min, zone_sec);
tzstring = tzbuf;
}
else
error ("Invalid time zone specification");
+ old_tzstring = getenv ("TZ");
+ if (old_tzstring)
+ {
+ char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1);
+ old_tzstring = strcpy (buf, old_tzstring);
+ }
+
block_input ();
/* Set TZ before calling mktime; merely adjusting mktime's returned
@@ -1929,15 +1950,12 @@
value = mktime (&tm);
- /* Restore TZ to previous value. */
- newenv = environ;
- environ = oldenv;
+ set_time_zone_rule (old_tzstring);
#ifdef LOCALTIME_CACHE
tzset ();
#endif
unblock_input ();
-
- xfree (newenv);
+ SAFE_FREE ();
}
if (value == (time_t) -1)
@@ -2067,16 +2085,6 @@
return list2 (zone_offset, zone_name);
}
-/* This holds the value of `environ' produced by the previous
- call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
- has never been called. */
-static char **environbuf;
-
-/* This holds the startup value of the TZ environment variable so it
- can be restored if the user calls set-time-zone-rule with a nil
- argument. */
-static char *initial_tz;
-
DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
doc: /* Set the local time zone using TZ, a string specifying a time
zone rule.
If TZ is nil, use implementation-defined default time zone information.
@@ -2089,18 +2097,10 @@
(Lisp_Object tz)
{
const char *tzstring;
- char **old_environbuf;
if (! (NILP (tz) || EQ (tz, Qt)))
CHECK_STRING (tz);
- block_input ();
-
- /* When called for the first time, save the original TZ. */
- old_environbuf = environbuf;
- if (!old_environbuf)
- initial_tz = (char *) getenv ("TZ");
-
if (NILP (tz))
tzstring = initial_tz;
else if (EQ (tz, Qt))
@@ -2108,106 +2108,97 @@
else
tzstring = SSDATA (tz);
+ block_input ();
set_time_zone_rule (tzstring);
- environbuf = environ;
-
unblock_input ();
- xfree (old_environbuf);
return Qnil;
}
-#ifdef LOCALTIME_CACHE
-
-/* These two values are known to load tz files in buggy implementations,
- i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
- Their values shouldn't matter in non-buggy implementations.
- We don't use string literals for these strings,
- since if a string in the environment is in readonly
- storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
- See Sun bugs 1113095 and 1114114, ``Timezone routines
- improperly modify environment''. */
-
-static char set_time_zone_rule_tz1[] = "TZ=GMT+0";
-static char set_time_zone_rule_tz2[] = "TZ=GMT+1";
-
-#endif
-
/* Set the local time zone rule to TZSTRING.
- This allocates memory into `environ', which it is the caller's
- responsibility to free. */
+
+ This function is not thread-safe, partly because putenv, unsetenv
+ and tzset are not, and partly because of the static storage it
+ updates. Other threads that invoke localtime etc. may be adversely
+ affected while this function is executing. */
void
set_time_zone_rule (const char *tzstring)
{
- ptrdiff_t envptrs;
- char **from, **to, **newenv;
-
- /* Make the ENVIRON vector longer with room for TZSTRING. */
- for (from = environ; *from; from++)
- continue;
- envptrs = from - environ + 2;
- newenv = to = xmalloc (envptrs * sizeof *newenv
- + (tzstring ? strlen (tzstring) + 4 : 0));
-
- /* Add TZSTRING to the end of environ, as a value for TZ. */
+ /* A buffer holding a string of the form "TZ=value", intended
+ to be part of the environment. */
+ static char *tzvalbuf;
+ static ptrdiff_t tzvalbufsize;
+
+ int tzeqlen = sizeof "TZ=" - 1;
+
+#ifdef LOCALTIME_CACHE
+ /* These two values are known to load tz files in buggy implementations,
+ i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2.
+ Their values shouldn't matter in non-buggy implementations.
+ We don't use string literals for these strings,
+ since if a string in the environment is in readonly
+ storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
+ See Sun bugs 1113095 and 1114114, ``Timezone routines
+ improperly modify environment''. */
+
+ static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"]
+ = { "TZ=GMT+0", "TZ=GMT+1" };
+
+ /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
+ "US/Pacific" that loads a tz file, then changes to a value like
+ "XXX0" that does not load a tz file, and then changes back to
+ its original value, the last change is (incorrectly) ignored.
+ Also, if TZ changes twice in succession to values that do
+ not load a tz file, tzset can dump core (see Sun bug#1225179).
+ The following code works around these bugs. */
+
if (tzstring)
{
- char *t = (char *) (to + envptrs);
- strcpy (t, "TZ=");
- strcat (t, tzstring);
- *to++ = t;
- }
-
- /* Copy the old environ vector elements into NEWENV,
- but don't copy the TZ variable.
- So we have only one definition of TZ, which came from TZSTRING. */
- for (from = environ; *from; from++)
- if (strncmp (*from, "TZ=", 3) != 0)
- *to++ = *from;
- *to = 0;
-
- environ = newenv;
-
- /* If we do have a TZSTRING, NEWENV points to the vector slot where
- the TZ variable is stored. If we do not have a TZSTRING,
- TO points to the vector slot which has the terminating null. */
+ /* Temporarily set TZ to a value that loads a tz file
+ and that differs from tzstring. */
+ bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0;
+ xputenv (set_time_zone_rule_tz[eq0]);
+ }
+ else
+ {
+ /* The implied tzstring is unknown, so temporarily set TZ to
+ two different values that each load a tz file. */
+ xputenv (set_time_zone_rule_tz[0]);
+ tzset ();
+ xputenv (set_time_zone_rule_tz[1]);
+ }
+ tzset ();
+#endif
+
+ if (!tzstring)
+ {
+ unsetenv ("TZ");
+ tzvalbuf_in_environ = 0;
+ }
+ else
+ {
+ ptrdiff_t tzstringlen = strlen (tzstring);
+
+ if (tzvalbufsize <= tzeqlen + tzstringlen)
+ {
+ unsetenv ("TZ");
+ tzvalbuf_in_environ = 0;
+ tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize,
+ tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
+ memcpy (tzvalbuf, "TZ=", tzeqlen);
+ }
+
+ strcpy (tzvalbuf + tzeqlen, tzstring);
+
+ if (!tzvalbuf_in_environ)
+ {
+ xputenv (tzvalbuf);
+ tzvalbuf_in_environ = 1;
+ }
+ }
#ifdef LOCALTIME_CACHE
- {
- /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
- "US/Pacific" that loads a tz file, then changes to a value like
- "XXX0" that does not load a tz file, and then changes back to
- its original value, the last change is (incorrectly) ignored.
- Also, if TZ changes twice in succession to values that do
- not load a tz file, tzset can dump core (see Sun bug#1225179).
- The following code works around these bugs. */
-
- if (tzstring)
- {
- /* Temporarily set TZ to a value that loads a tz file
- and that differs from tzstring. */
- char *tz = *newenv;
- *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
- ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
- tzset ();
- *newenv = tz;
- }
- else
- {
- /* The implied tzstring is unknown, so temporarily set TZ to
- two different values that each load a tz file. */
- *to = set_time_zone_rule_tz1;
- to[1] = 0;
- tzset ();
- *to = set_time_zone_rule_tz2;
- tzset ();
- *to = 0;
- }
-
- /* Now TZ has the desired value, and tzset can be invoked safely. */
- }
-
tzset ();
#endif
}
@@ -4800,9 +4791,6 @@
void
syms_of_editfns (void)
{
- environbuf = 0;
- initial_tz = 0;
-
DEFSYM (Qbuffer_access_fontify_functions, "buffer-access-fontify-functions");
DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
=== modified file 'src/emacs.c'
--- a/src/emacs.c 2012-11-21 04:47:55 +0000
+++ b/src/emacs.c 2012-12-08 17:19:51 +0000
@@ -535,7 +535,7 @@
#ifdef HAVE_TZSET
/* A valid but unlikely value for the TZ environment value.
It is OK (though a bit slower) if the user actually chooses this value. */
-static char dump_tz[] = "UtC0";
+static char const dump_tz[] = "UtC0";
#endif
#ifndef ORDINARY_LINK
@@ -717,7 +717,7 @@
#ifdef G_SLICE_ALWAYS_MALLOC
/* This is used by the Cygwin build. */
- setenv ("G_SLICE", "always-malloc", 1);
+ xputenv ("G_SLICE=always-malloc");
#endif
#ifdef GNU_LINUX
@@ -803,9 +803,8 @@
#ifdef HAVE_PERSONALITY_LINUX32
if (dumping && ! getenv ("EMACS_HEAP_EXEC"))
{
- static char heapexec[] = "EMACS_HEAP_EXEC=true";
/* Set this so we only do this once. */
- putenv (heapexec);
+ xputenv ("EMACS_HEAP_EXEC=true");
/* A flag to turn off address randomization which is introduced
in linux kernel shipped with fedora core 4 */
@@ -1309,7 +1308,7 @@
don't pollute Vglobal_environment. */
/* Setting LANG here will defeat the startup locale processing... */
#ifdef AIX
- putenv ("LANG=C");
+ xputenv ("LANG=C");
#endif
init_buffer (); /* Init default directory of main buffer. */
=== modified file 'src/lisp.h'
--- a/src/lisp.h 2012-12-04 15:15:30 +0000
+++ b/src/lisp.h 2012-12-08 17:19:51 +0000
@@ -3594,6 +3594,7 @@
extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t);
extern char *xstrdup (const char *);
+extern void xputenv (const char *);
extern char *egetenv (const char *);
=== modified file 'src/xterm.c'
--- a/src/xterm.c 2012-12-04 15:15:30 +0000
+++ b/src/xterm.c 2012-12-08 17:19:51 +0000
@@ -9908,10 +9908,7 @@
/* Emacs can only handle core input events, so make sure
Gtk doesn't use Xinput or Xinput2 extensions. */
- {
- static char fix_events[] = "GDK_CORE_DEVICE_EVENTS=1";
- putenv (fix_events);
- }
+ xputenv ("GDK_CORE_DEVICE_EVENTS=1");
/* Work around GLib bug that outputs a faulty warning. See
https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] /srv/bzr/emacs/trunk r111158: Use putenv+unsetenv instead of modifying environ directly.,
Paul Eggert <=