Skip to content

bpo-39406: Implement os.putenv() with setenv() if available #18128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 5 additions & 5 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 20 additions & 18 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -10142,7 +10139,8 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
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

Expand All @@ -10157,31 +10155,35 @@ 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);

if (strchr(name_string, '=') != NULL) {
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
Expand Down
17 changes: 3 additions & 14 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,6 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
Expand Down Expand Up @@ -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}'
Expand Down Expand Up @@ -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=* \
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 \
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 3 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down