Skip to content

Commit b477d19

Browse files
authored
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.
1 parent 0852c7d commit b477d19

File tree

6 files changed

+35
-38
lines changed

6 files changed

+35
-38
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
If ``setenv()`` C function is available, :func:`os.putenv` is now
2+
implemented with ``setenv()`` instead of ``putenv()``, so Python doesn't
3+
have to handle the environment variable memory.

Modules/clinic/posixmodule.c.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -819,19 +819,20 @@ dir_fd_converter(PyObject *o, void *p)
819819
}
820820
}
821821

822-
/* Windows: _wputenv(env) copies the *env* string and doesn't require the
823-
caller to manage the variable memory. */
824-
#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS)
822+
/* Windows _wputenv() and setenv() copy the arguments and so don't require
823+
the caller to manage the variable memory. Only Unix putenv() requires
824+
putenv_dict. */
825+
#if defined(HAVE_PUTENV) && !defined(MS_WINDOWS) && !defined(HAVE_SETENV)
825826
# define PY_PUTENV_DICT
826827
#endif
827828

828829
typedef struct {
829830
PyObject *billion;
830831
#ifdef PY_PUTENV_DICT
831-
/* putenv() and _wputenv() requires that the caller manages the environment
832-
variable memory. Use a Python dictionary for that: name => env, where
833-
env is a string like "name=value". On Windows, dict keys and values are
834-
Unicode strings. On Unix, they are bytes strings. */
832+
/* putenv() requires that the caller manages the environment variable
833+
memory. Use a Python dictionary for that: name => env, where env is a
834+
string like "name=value". On Windows, dict keys and values are Unicode
835+
strings. On Unix, they are bytes strings. */
835836
PyObject *putenv_dict;
836837
#endif
837838
PyObject *DirEntryType;
@@ -10081,8 +10082,6 @@ posix_putenv_dict_setitem(PyObject *name, PyObject *value)
1008110082
#endif /* PY_PUTENV_DICT */
1008210083

1008310084

10084-
#ifdef HAVE_PUTENV
10085-
1008610085
#ifdef MS_WINDOWS
1008710086
/*[clinic input]
1008810087
os.putenv
@@ -10132,8 +10131,6 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1013210131
posix_error();
1013310132
goto error;
1013410133
}
10135-
/* _wputenv(env) copies the *env* string and doesn't require the caller
10136-
to manage the variable memory. */
1013710134
Py_DECREF(unicode);
1013810135

1013910136
Py_RETURN_NONE;
@@ -10142,7 +10139,8 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1014210139
Py_DECREF(unicode);
1014310140
return NULL;
1014410141
}
10145-
#else /* MS_WINDOWS */
10142+
/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */
10143+
#elif (defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && !defined(MS_WINDOWS)
1014610144
/*[clinic input]
1014710145
os.putenv
1014810146
@@ -10157,31 +10155,35 @@ static PyObject *
1015710155
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1015810156
/*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
1015910157
{
10160-
PyObject *bytes = NULL;
10161-
char *env;
1016210158
const char *name_string = PyBytes_AS_STRING(name);
1016310159
const char *value_string = PyBytes_AS_STRING(value);
1016410160

1016510161
if (strchr(name_string, '=') != NULL) {
1016610162
PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
1016710163
return NULL;
1016810164
}
10169-
bytes = PyBytes_FromFormat("%s=%s", name_string, value_string);
10165+
10166+
#ifdef HAVE_SETENV
10167+
if (setenv(name_string, value_string, 1)) {
10168+
return posix_error();
10169+
}
10170+
#else
10171+
PyObject *bytes = PyBytes_FromFormat("%s=%s", name_string, value_string);
1017010172
if (bytes == NULL) {
1017110173
return NULL;
1017210174
}
1017310175

10174-
env = PyBytes_AS_STRING(bytes);
10176+
char *env = PyBytes_AS_STRING(bytes);
1017510177
if (putenv(env)) {
1017610178
Py_DECREF(bytes);
1017710179
return posix_error();
1017810180
}
1017910181

1018010182
posix_putenv_dict_setitem(name, bytes);
10183+
#endif
1018110184
Py_RETURN_NONE;
1018210185
}
10183-
#endif /* MS_WINDOWS */
10184-
#endif /* HAVE_PUTENV */
10186+
#endif /* defined(HAVE_SETENV) || defined(HAVE_PUTENV) */
1018510187

1018610188

1018710189
#ifdef HAVE_UNSETENV

configure

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,6 @@ infodir
782782
docdir
783783
oldincludedir
784784
includedir
785-
runstatedir
786785
localstatedir
787786
sharedstatedir
788787
sysconfdir
@@ -896,7 +895,6 @@ datadir='${datarootdir}'
896895
sysconfdir='${prefix}/etc'
897896
sharedstatedir='${prefix}/com'
898897
localstatedir='${prefix}/var'
899-
runstatedir='${localstatedir}/run'
900898
includedir='${prefix}/include'
901899
oldincludedir='/usr/include'
902900
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1149,15 +1147,6 @@ do
11491147
| -silent | --silent | --silen | --sile | --sil)
11501148
silent=yes ;;
11511149

1152-
-runstatedir | --runstatedir | --runstatedi | --runstated \
1153-
| --runstate | --runstat | --runsta | --runst | --runs \
1154-
| --run | --ru | --r)
1155-
ac_prev=runstatedir ;;
1156-
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
1157-
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
1158-
| --run=* | --ru=* | --r=*)
1159-
runstatedir=$ac_optarg ;;
1160-
11611150
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
11621151
ac_prev=sbindir ;;
11631152
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1295,7 +1284,7 @@ fi
12951284
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
12961285
datadir sysconfdir sharedstatedir localstatedir includedir \
12971286
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
1298-
libdir localedir mandir runstatedir
1287+
libdir localedir mandir
12991288
do
13001289
eval ac_val=\$$ac_var
13011290
# Remove trailing slashes.
@@ -1448,7 +1437,6 @@ Fine tuning of the installation directories:
14481437
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
14491438
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
14501439
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
1451-
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
14521440
--libdir=DIR object code libraries [EPREFIX/lib]
14531441
--includedir=DIR C header files [PREFIX/include]
14541442
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -10303,6 +10291,7 @@ fi
1030310291

1030410292

1030510293

10294+
1030610295
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
1030710296
if test -n "$ac_tool_prefix"; then
1030810297
# 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 \
1156111550
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
1156211551
pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \
1156311552
readlink readlinkat readv realpath renameat \
11564-
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
11553+
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \
1156511554
setgid sethostname \
1156611555
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
1156711556
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3600,7 +3600,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
36003600
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
36013601
pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \
36023602
readlink readlinkat readv realpath renameat \
3603-
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
3603+
sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid setenv seteuid \
36043604
setgid sethostname \
36053605
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
36063606
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@
895895
/* Define to 1 if you have the `setegid' function. */
896896
#undef HAVE_SETEGID
897897

898+
/* Define to 1 if you have the `setenv' function. */
899+
#undef HAVE_SETENV
900+
898901
/* Define to 1 if you have the `seteuid' function. */
899902
#undef HAVE_SETEUID
900903

0 commit comments

Comments
 (0)