@@ -1792,21 +1792,59 @@ static PyObject *
17921792convertenviron(void)
17931793{
17941794 PyObject *d;
1795- #ifdef MS_WINDOWS
1796- wchar_t **e;
1797- #else
1798- char **e;
1799- #endif
18001795
18011796 d = PyDict_New();
18021797 if (d == NULL)
18031798 return NULL;
18041799#ifdef MS_WINDOWS
1805- /* _wenviron must be initialized in this way if the program is started
1806- through main() instead of wmain(). */
1807- (void)_wgetenv(L"");
1808- e = _wenviron;
1809- #elif defined(USE_DARWIN_NS_GET_ENVIRON)
1800+ wchar_t *environment = GetEnvironmentStringsW();
1801+ if (environment == NULL) {
1802+ Py_DECREF(d);
1803+ return PyErr_SetFromWindowsErr(0);
1804+ }
1805+
1806+ for (wchar_t *entry = environment; *entry != L'\0';
1807+ entry += wcslen(entry) + 1)
1808+ {
1809+ /* Entries whose names start with '=' are hidden drive-current-
1810+ directory variables. The CRT does not expose them, so continue
1811+ to omit them from os.environ. */
1812+ if (*entry == L'=') {
1813+ continue;
1814+ }
1815+
1816+ const wchar_t *p = wcschr(entry, L'=');
1817+ if (p == NULL) {
1818+ continue;
1819+ }
1820+
1821+ PyObject *k = PyUnicode_FromWideChar(entry, (Py_ssize_t)(p - entry));
1822+ if (k == NULL) {
1823+ FreeEnvironmentStringsW(environment);
1824+ Py_DECREF(d);
1825+ return NULL;
1826+ }
1827+ PyObject *v = PyUnicode_FromWideChar(p + 1, -1);
1828+ if (v == NULL) {
1829+ Py_DECREF(k);
1830+ FreeEnvironmentStringsW(environment);
1831+ Py_DECREF(d);
1832+ return NULL;
1833+ }
1834+ if (PyDict_SetDefaultRef(d, k, v, NULL) < 0) {
1835+ Py_DECREF(v);
1836+ Py_DECREF(k);
1837+ FreeEnvironmentStringsW(environment);
1838+ Py_DECREF(d);
1839+ return NULL;
1840+ }
1841+ Py_DECREF(k);
1842+ Py_DECREF(v);
1843+ }
1844+ FreeEnvironmentStringsW(environment);
1845+ #else
1846+ char **e;
1847+ #ifdef USE_DARWIN_NS_GET_ENVIRON
18101848 /* environ is not accessible as an extern in a shared object on OSX; use
18111849 _NSGetEnviron to resolve it. The value changes if you add environment
18121850 variables between calls to Py_Initialize, so don't cache the value. */
@@ -1817,29 +1855,16 @@ convertenviron(void)
18171855 if (e == NULL)
18181856 return d;
18191857 for (; *e != NULL; e++) {
1820- PyObject *k;
1821- PyObject *v;
1822- #ifdef MS_WINDOWS
1823- const wchar_t *p = wcschr(*e, L'=');
1824- #else
18251858 const char *p = strchr(*e, '=');
1826- #endif
18271859 if (p == NULL)
18281860 continue;
1829- #ifdef MS_WINDOWS
1830- k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
1831- #else
1832- k = PyBytes_FromStringAndSize(*e, (Py_ssize_t)(p-*e));
1833- #endif
1861+
1862+ PyObject *k = PyBytes_FromStringAndSize(*e, (Py_ssize_t)(p - *e));
18341863 if (k == NULL) {
18351864 Py_DECREF(d);
18361865 return NULL;
18371866 }
1838- #ifdef MS_WINDOWS
1839- v = PyUnicode_FromWideChar(p+1, -1);
1840- #else
1841- v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
1842- #endif
1867+ PyObject *v = PyBytes_FromStringAndSize(p + 1, strlen(p + 1));
18431868 if (v == NULL) {
18441869 Py_DECREF(k);
18451870 Py_DECREF(d);
@@ -1854,6 +1879,7 @@ convertenviron(void)
18541879 Py_DECREF(k);
18551880 Py_DECREF(v);
18561881 }
1882+ #endif
18571883 return d;
18581884}
18591885
@@ -13777,6 +13803,25 @@ win32_putenv(PyObject *name, PyObject *value)
1377713803 PyMem_Free(env);
1377813804 return NULL;
1377913805 }
13806+
13807+ if (value != NULL && PyUnicode_GET_LENGTH(value) == 0) {
13808+ /* The CRT treats "NAME=" as removing NAME. Preserve the empty value
13809+ in the PEB so that os.environ, os.reload_environ(), and child
13810+ processes observe the value requested by the Python caller. */
13811+ wchar_t *name_wstr = PyUnicode_AsWideCharString(name, NULL);
13812+ if (name_wstr == NULL) {
13813+ PyMem_Free(env);
13814+ return NULL;
13815+ }
13816+ if (!SetEnvironmentVariableW(name_wstr, L"")) {
13817+ DWORD error = GetLastError();
13818+ PyMem_Free(name_wstr);
13819+ PyMem_Free(env);
13820+ return PyErr_SetFromWindowsErr(error);
13821+ }
13822+ PyMem_Free(name_wstr);
13823+ }
13824+
1378013825 PyMem_Free(env);
1378113826
1378213827 Py_RETURN_NONE;
0 commit comments