-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
[WIP] bpo-39413: os.unsetenv() uses _wputenv() on Windows #18115
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10079,53 +10079,31 @@ posix_putenv_dict_setitem(PyObject *name, PyObject *value) | |
#endif /* PY_PUTENV_DICT */ | ||
|
||
|
||
#ifdef HAVE_PUTENV | ||
|
||
#ifdef MS_WINDOWS | ||
/*[clinic input] | ||
os.putenv | ||
|
||
name: unicode | ||
value: unicode | ||
/ | ||
|
||
Change or add an environment variable. | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) | ||
/*[clinic end generated code: output=d29a567d6b2327d2 input=ba586581c2e6105f]*/ | ||
static PyObject* | ||
py_win_putenv(PyObject *name, PyObject *value) | ||
{ | ||
const wchar_t *env; | ||
Py_ssize_t size; | ||
|
||
/* Search from index 1 because on Windows starting '=' is allowed for | ||
defining hidden environment variables. */ | ||
if (PyUnicode_GET_LENGTH(name) == 0 || | ||
PyUnicode_FindChar(name, '=', 1, PyUnicode_GET_LENGTH(name), 1) != -1) | ||
{ | ||
PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); | ||
return NULL; | ||
} | ||
PyObject *unicode = PyUnicode_FromFormat("%U=%U", name, value); | ||
if (unicode == NULL) { | ||
return NULL; | ||
} | ||
|
||
env = PyUnicode_AsUnicodeAndSize(unicode, &size); | ||
if (env == NULL) | ||
const wchar_t *env; | ||
Py_ssize_t size; | ||
/* PyUnicode_AsWideCharString() rejects embedded null characters */ | ||
env = PyUnicode_AsWideCharString(unicode, &size); | ||
if (env == NULL) { | ||
goto error; | ||
} | ||
if (size > _MAX_ENV) { | ||
PyErr_Format(PyExc_ValueError, | ||
"the environment variable is longer than %u characters", | ||
_MAX_ENV); | ||
goto error; | ||
} | ||
if (wcslen(env) != (size_t)size) { | ||
PyErr_SetString(PyExc_ValueError, "embedded null character"); | ||
goto error; | ||
} | ||
|
||
/* Use _wputenv() rather than SetEnvironmentVariableW(): _wputenv() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The search for "=" (line 10102) should begin at index 0, not index 1. Windows allows variable names that begin with 0, but ucrt does not allow it. For example: >>> os.putenv('spam=', 'eggs')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: illegal environment variable name
>>> os.putenv('=spam', 'eggs')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed this surprising difference and I'm trying to understand what should be the correct behavior... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it work with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python initializes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to allow setting them, then Python should initialize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about
Because in "key==value" what is a key and what is a value? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Windows is so weird. The official documentation says:
I tested: I can set a variable with name "zlong=" (the name contains "="). It is shown by the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked back to even Python 2.7 w/ msvcr90.dll, and even that old version of the CRT copies the string that's passed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Fixed in commit 0852c7d. |
||
updates the CRT, whereas SetEnvironmentVariableW() does not. */ | ||
if (_wputenv(env)) { | ||
posix_error(); | ||
goto error; | ||
|
@@ -10138,7 +10116,37 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) | |
Py_DECREF(unicode); | ||
return NULL; | ||
} | ||
#else /* MS_WINDOWS */ | ||
#endif | ||
|
||
|
||
#ifdef MS_WINDOWS | ||
/*[clinic input] | ||
os.putenv | ||
|
||
name: unicode | ||
value: unicode | ||
/ | ||
|
||
Change or add an environment variable. | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) | ||
/*[clinic end generated code: output=d29a567d6b2327d2 input=ba586581c2e6105f]*/ | ||
{ | ||
/* Search from index 1 because on Windows starting '=' is allowed for | ||
defining hidden environment variables. */ | ||
if (PyUnicode_GET_LENGTH(name) == 0 || | ||
PyUnicode_FindChar(name, '=', 1, PyUnicode_GET_LENGTH(name), 1) != -1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, this search should start at index 0, so that it consistently raises |
||
{ | ||
PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); | ||
return NULL; | ||
} | ||
|
||
return py_win_putenv(name, value); | ||
} | ||
/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */ | ||
#elif defined(HAVE_PUTENV) && !defined(MS_WINDOWS) | ||
/*[clinic input] | ||
os.putenv | ||
|
||
|
@@ -10176,8 +10184,7 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) | |
posix_putenv_dict_setitem(name, bytes); | ||
Py_RETURN_NONE; | ||
} | ||
#endif /* MS_WINDOWS */ | ||
#endif /* HAVE_PUTENV */ | ||
#endif /* defined(HAVE_PUTENV) && !defined(MS_WINDOWS) */ | ||
|
||
|
||
#ifdef MS_WINDOWS | ||
|
@@ -10193,35 +10200,16 @@ static PyObject * | |
os_unsetenv_impl(PyObject *module, PyObject *name) | ||
/*[clinic end generated code: output=54c4137ab1834f02 input=4d6a1747cc526d2f]*/ | ||
{ | ||
/* PyUnicode_AsWideCharString() rejects embedded null characters */ | ||
wchar_t *name_str = PyUnicode_AsWideCharString(name, NULL); | ||
if (name_str == NULL) { | ||
PyObject *empty = PyUnicode_New(0, 0); | ||
if (empty == NULL) { | ||
return NULL; | ||
} | ||
|
||
BOOL ok = SetEnvironmentVariableW(name_str, NULL); | ||
PyMem_Free(name_str); | ||
|
||
if (!ok) { | ||
return PyErr_SetFromWindowsErr(0); | ||
} | ||
/* _wputenv("name=") removes the environment variable "name" */ | ||
PyObject *res = py_win_putenv(name, empty); | ||
Py_DECREF(empty); | ||
|
||
#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)->putenv_dict, name)) { | ||
/* really not much we can do; just leak */ | ||
if (!PyErr_ExceptionMatches(PyExc_KeyError)) { | ||
return NULL; | ||
} | ||
PyErr_Clear(); | ||
} | ||
#endif | ||
|
||
Py_RETURN_NONE; | ||
return res; | ||
} | ||
/* repeat !defined(MS_WINDOWS) to workaround an Argument Clinic issue */ | ||
#elif defined(HAVE_UNSETENV) && !defined(MS_WINDOWS) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
py_win_
the naming convention from now on -- as opposed towin32_
?