Skip to content

bpo-39406: Add PY_PUTENV_DICT macro to posixmodule.c #18106

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 1 commit into from
Jan 21, 2020
Merged
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
52 changes: 37 additions & 15 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,9 +819,19 @@ dir_fd_converter(PyObject *o, void *p)
}
}

#ifdef HAVE_PUTENV
# define PY_PUTENV_DICT
#endif

typedef struct {
PyObject *billion;
PyObject *posix_putenv_garbage;
#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. */
PyObject *putenv_dict;
#endif
PyObject *DirEntryType;
PyObject *ScandirIteratorType;
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
Expand Down Expand Up @@ -2105,7 +2115,9 @@ static int
_posix_clear(PyObject *module)
{
Py_CLEAR(_posixstate(module)->billion);
Py_CLEAR(_posixstate(module)->posix_putenv_garbage);
#ifdef PY_PUTENV_DICT
Py_CLEAR(_posixstate(module)->putenv_dict);
#endif
Py_CLEAR(_posixstate(module)->DirEntryType);
Py_CLEAR(_posixstate(module)->ScandirIteratorType);
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
Expand All @@ -2130,7 +2142,9 @@ static int
_posix_traverse(PyObject *module, visitproc visit, void *arg)
{
Py_VISIT(_posixstate(module)->billion);
Py_VISIT(_posixstate(module)->posix_putenv_garbage);
#ifdef PY_PUTENV_DICT
Py_VISIT(_posixstate(module)->putenv_dict);
#endif
Py_VISIT(_posixstate(module)->DirEntryType);
Py_VISIT(_posixstate(module)->ScandirIteratorType);
#if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
Expand Down Expand Up @@ -10047,23 +10061,26 @@ os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset,
}
#endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */

#ifdef HAVE_PUTENV

#ifdef PY_PUTENV_DICT
static void
posix_putenv_garbage_setitem(PyObject *name, PyObject *value)
posix_putenv_dict_setitem(PyObject *name, PyObject *value)
{
/* Install the first arg and newstr in posix_putenv_garbage;
/* Install the first arg and newstr in putenv_dict;
* this will cause previous value to be collected. This has to
* happen after the real putenv() call because the old value
* was still accessible until then. */
if (PyDict_SetItem(_posixstate_global->posix_putenv_garbage, name, value))
if (PyDict_SetItem(_posixstate_global->putenv_dict, name, value))
/* really not much we can do; just leak */
PyErr_Clear();
else
Py_DECREF(value);
}
#endif /* PY_PUTENV_DICT */


#ifdef HAVE_PUTENV

#ifdef MS_WINDOWS
/*[clinic input]
os.putenv
Expand Down Expand Up @@ -10114,7 +10131,7 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
goto error;
}

posix_putenv_garbage_setitem(name, unicode);
posix_putenv_dict_setitem(name, unicode);
Py_RETURN_NONE;

error:
Expand Down Expand Up @@ -10156,7 +10173,7 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
return posix_error();
}

posix_putenv_garbage_setitem(name, bytes);
posix_putenv_dict_setitem(name, bytes);
Py_RETURN_NONE;
}
#endif /* MS_WINDOWS */
Expand Down Expand Up @@ -10189,18 +10206,20 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
return PyErr_SetFromWindowsErr(0);
}

/* Remove the key from posix_putenv_garbage;
#ifdef PY_PUTENV_DICT
/* Remove the key from putenv_dict;
* this will cause it to be collected. This has to
* happen after the real unsetenv() call because the
* old value was still accessible until then.
*/
if (PyDict_DelItem(_posixstate(module)->posix_putenv_garbage, name)) {
if (PyDict_DelItem(_posixstate(module)->putenv_dict, name)) {
/* really not much we can do; just leak */
if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
return NULL;
}
PyErr_Clear();
}
#endif

Py_RETURN_NONE;
}
Expand Down Expand Up @@ -10230,18 +10249,21 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
return posix_error();
#endif

/* Remove the key from posix_putenv_garbage;
#ifdef PY_PUTENV_DICT
/* Remove the key from putenv_dict;
* this will cause it to be collected. This has to
* happen after the real unsetenv() call because the
* old value was still accessible until then.
*/
if (PyDict_DelItem(_posixstate(module)->posix_putenv_garbage, name)) {
if (PyDict_DelItem(_posixstate(module)->putenv_dict, name)) {
/* really not much we can do; just leak */
if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
return NULL;
}
PyErr_Clear();
}
#endif

Py_RETURN_NONE;
}
#endif /* HAVE_UNSETENV */
Expand Down Expand Up @@ -14538,10 +14560,10 @@ INITFUNC(void)
Py_INCREF(PyExc_OSError);
PyModule_AddObject(m, "error", PyExc_OSError);

#ifdef HAVE_PUTENV
#ifdef PY_PUTENV_DICT
/* Save putenv() parameters as values here, so we can collect them when they
* get re-set with another call for the same key. */
_posixstate(m)->posix_putenv_garbage = PyDict_New();
_posixstate(m)->putenv_dict = PyDict_New();
#endif

#if defined(HAVE_WAITID) && !defined(__APPLE__)
Expand Down