From b477d19a6b7751b0c933b239dae4fc96dbcde9c4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 22 Jan 2020 22:48:16 +0100 Subject: [PATCH] bpo-39406: Implement os.putenv() with setenv() if available (GH-18128) If setenv() C function is available, os.putenv() is now implemented with setenv() instead of putenv(), so Python doesn't have to handle the environment variable memory. --- .../2020-01-22-21-18-58.bpo-39406.HMpe8x.rst | 3 ++ Modules/clinic/posixmodule.c.h | 10 ++--- Modules/posixmodule.c | 38 ++++++++++--------- configure | 17 ++------- configure.ac | 2 +- pyconfig.h.in | 3 ++ 6 files changed, 35 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-01-22-21-18-58.bpo-39406.HMpe8x.rst diff --git a/Misc/NEWS.d/next/Library/2020-01-22-21-18-58.bpo-39406.HMpe8x.rst b/Misc/NEWS.d/next/Library/2020-01-22-21-18-58.bpo-39406.HMpe8x.rst new file mode 100644 index 00000000000..56a53160432 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-01-22-21-18-58.bpo-39406.HMpe8x.rst @@ -0,0 +1,3 @@ +If ``setenv()`` C function is available, :func:`os.putenv` is now +implemented with ``setenv()`` instead of ``putenv()``, so Python doesn't +have to handle the environment variable memory. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index aa4756a620a..13a69cd5f0e 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -6034,7 +6034,7 @@ exit: #endif /* (defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)) */ -#if defined(HAVE_PUTENV) && defined(MS_WINDOWS) +#if defined(MS_WINDOWS) PyDoc_STRVAR(os_putenv__doc__, "putenv($module, name, value, /)\n" @@ -6080,9 +6080,9 @@ exit: return return_value; } -#endif /* defined(HAVE_PUTENV) && defined(MS_WINDOWS) */ +#endif /* defined(MS_WINDOWS) */ -#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS) +#if ((defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS)) PyDoc_STRVAR(os_putenv__doc__, "putenv($module, name, value, /)\n" @@ -6123,7 +6123,7 @@ exit: return return_value; } -#endif /* defined(HAVE_PUTENV) && !defined(MS_WINDOWS) */ +#endif /* ((defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS)) */ #if defined(HAVE_UNSETENV) @@ -8773,4 +8773,4 @@ exit: #ifndef OS__REMOVE_DLL_DIRECTORY_METHODDEF #define OS__REMOVE_DLL_DIRECTORY_METHODDEF #endif /* !defined(OS__REMOVE_DLL_DIRECTORY_METHODDEF) */ -/*[clinic end generated code: output=51ba5b9536420cea input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6f42d8be634f5942 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 71b99fd836f..6a687529df0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -819,19 +819,20 @@ dir_fd_converter(PyObject *o, void *p) } } -/* Windows: _wputenv(env) copies the *env* string and doesn't require the - caller to manage the variable memory. */ -#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS) +/* Windows _wputenv() and setenv() copy the arguments and so don't require + the caller to manage the variable memory. Only Unix putenv() requires + putenv_dict. */ +#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS) && !defined(HAVE_SETENV) # define PY_PUTENV_DICT #endif typedef struct { PyObject *billion; #ifdef PY_PUTENV_DICT - /* putenv() and _wputenv() requires that the caller manages the environment - variable memory. Use a Python dictionary for that: name => env, where - env is a string like "name=value". On Windows, dict keys and values are - Unicode strings. On Unix, they are bytes strings. */ + /* putenv() requires that the caller manages the environment variable + memory. Use a Python dictionary for that: name => env, where env is a + string like "name=value". On Windows, dict keys and values are Unicode + strings. On Unix, they are bytes strings. */ PyObject *putenv_dict; #endif PyObject *DirEntryType; @@ -10081,8 +10082,6 @@ posix_putenv_dict_setitem(PyObject *name, PyObject *value) #endif /* PY_PUTENV_DICT */ -#ifdef HAVE_PUTENV - #ifdef MS_WINDOWS /*[clinic input] os.putenv @@ -10132,8 +10131,6 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) posix_error(); goto error; } - /* _wputenv(env) copies the *env* string and doesn't require the caller - to manage the variable memory. */ Py_DECREF(unicode); Py_RETURN_NONE; @@ -10142,7 +10139,8 @@ error: Py_DECREF(unicode); return NULL; } -#else /* MS_WINDOWS */ +/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */ +#elif (defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS) /*[clinic input] os.putenv @@ -10157,8 +10155,6 @@ static PyObject * os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) /*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/ { - PyObject *bytes = NULL; - char *env; const char *name_string = PyBytes_AS_STRING(name); const char *value_string = PyBytes_AS_STRING(value); @@ -10166,22 +10162,28 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); return NULL; } - bytes = PyBytes_FromFormat("%s=%s", name_string, value_string); + +#ifdef HAVE_SETENV + if (setenv(name_string, value_string, 1)) { + return posix_error(); + } +#else + PyObject *bytes = PyBytes_FromFormat("%s=%s", name_string, value_string); if (bytes == NULL) { return NULL; } - env = PyBytes_AS_STRING(bytes); + char *env = PyBytes_AS_STRING(bytes); if (putenv(env)) { Py_DECREF(bytes); return posix_error(); } posix_putenv_dict_setitem(name, bytes); +#endif Py_RETURN_NONE; } -#endif /* MS_WINDOWS */ -#endif /* HAVE_PUTENV */ +#endif /* defined(HAVE_SETENV) || defined(HAVE_PUTENV) */ #ifdef HAVE_UNSETENV diff --git a/configure b/configure index c8253b1455f..e96683622b3 100755 --- a/configure +++ b/configure @@ -782,7 +782,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -896,7 +895,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1149,15 +1147,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1295,7 +1284,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1448,7 +1437,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -10303,6 +10291,7 @@ fi + if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. @@ -11561,7 +11550,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \ pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \ readlink readlinkat readv realpath renameat \ - sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ + sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \ setgid sethostname \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \ sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \ diff --git a/configure.ac b/configure.ac index bcef99c4962..36c165b2f2e 100644 --- a/configure.ac +++ b/configure.ac @@ -3600,7 +3600,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \ pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \ readlink readlinkat readv realpath renameat \ - sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ + sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \ setgid sethostname \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \ sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \ diff --git a/pyconfig.h.in b/pyconfig.h.in index e053be15a11..1918fab8bdb 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -895,6 +895,9 @@ /* Define to 1 if you have the `setegid' function. */ #undef HAVE_SETEGID +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID