classification
Title: The os module should unset() environment variable at exit
Type: crash Stage: resolved
Components: Interpreter Core Versions: Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: eric.snow, serhiy.storchaka, vstinner
Priority: normal Keywords: patch

Created on 2020-01-20 11:58 by vstinner, last changed 2020-01-24 20:35 by eric.snow. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 18078 closed vstinner, 2020-01-20 12:18
PR 18135 merged vstinner, 2020-01-23 02:07
Messages (10)
msg360309 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-20 11:58
os.environ[key] = value has to keep internally the string "key=value\0" after putenv("key=value\0") has been called, since the glibc doesn't copy the string. Python has to manage the string memory.

Internally, the posix module uses a "posix_putenv_garbage" dictionary mapping key (bytes) to value (bytes). Values are "key=value\0" strings.

The bpo-35381 issue converted the os ("posix" in practice) module PEP 384: "Remove all static state from posixmodule": commit b3966639d28313809774ca3859a347b9007be8d2. The _posix_clear() function is now called by _PyImport_Cleanup().

Problem: the glibc is not aware that Python is exiting and that the memory of the environment variable has been released. Next access to environment variables ("environ" C variable, putenv, setenv, unsetenv, ...) can crash. Sometimes, it doesn't crash even if the memory has been released, because free() does not always dig immediately holes in the heap memory (the complex problelm of memory fragmentation).

The posix module should notify the glibc that the memory will be released before releasing the memory, to avoid keeping dangling pointers in the "environ" C variable.

The following crash in the Elements module is an example of crash introduced by commit b3966639d28313809774ca3859a347b9007be8d2 which introduced this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=1791761
msg360368 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-21 08:53
Fedora downstream issue, crash in the "elements" package: https://bugzilla.redhat.com/show_bug.cgi?id=1791761
msg360369 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-21 08:57
I proposed bpo-39406 which avoids to have to clear environment variables set by Python at exit on platforms providing setenv().
msg360471 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-01-22 14:57
Issue39406 is a new feature. In any case we should fix potential crash in older Python versions.
msg360472 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-22 15:00
> Issue39406 is a new feature. In any case we should fix potential crash in older Python versions.

Python 3.8 and older are not affected by this issue since they never destroy the posix_putenv_garbage dictionary: memory is never released.
msg360515 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-22 22:03
I closed bpo-39406: os.putenv() is now implemented with setenv() if available. The internal putenv_dict is no longer used on Windows and if setenv() is available.

Now only non-Windows platforms without setenv() are affected by this issue.
msg360530 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-23 02:11
Clearing environment variables at exit has a drawback: it changes the behavior in code executed after Python finalization (Py_FinalizeEx() call). It may cause regression.

So I proposed PR 18135 to fix this issue differently: on non-Windows platforms, Python now requires setenv() to build. This PR has no backward compatibility issue: it doesn't unset environment variables at exit.
msg360614 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-24 13:05
New changeset b8d1262e8afe7b907b4a394a191739571092acdb by Victor Stinner in branch 'master':
bpo-39395: putenv() and unsetenv() always available (GH-18135)
https://github.com/python/cpython/commit/b8d1262e8afe7b907b4a394a191739571092acdb
msg360615 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-01-24 13:12
On non-Windows platforms, Python now requires setenv() and unsetenv()
functions to build.

setenv() and unsetenv() should be available on all platforms supported by Python. If it's not the case, someone can maintain a downstream patch which is a revert of commit b8d1262e8afe7b907b4a394a191739571092acdb.

If someone asks to support a platform which doesn't provide setenv() and unsetenv(), we can revisit the idea of unsetting variables set by Python at exit, to workaround putenv() issue: something like my (abandonned) PR 18078.
msg360654 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2020-01-24 20:35
FTR, #39376 is related (avoid the process-global env vars in the first place).
History
Date User Action Args
2020-01-24 20:35:09eric.snowsetnosy: + eric.snow
messages: + msg360654
2020-01-24 13:12:45vstinnersetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2020-01-24 13:12:09vstinnersetmessages: + msg360615
2020-01-24 13:05:51vstinnersetmessages: + msg360614
2020-01-23 02:11:25vstinnersetmessages: + msg360530
2020-01-23 02:07:40vstinnersetpull_requests: + pull_request17521
2020-01-22 22:03:22vstinnersetmessages: + msg360515
2020-01-22 15:00:11vstinnersetversions: - Python 3.7, Python 3.8
2020-01-22 15:00:03vstinnersetmessages: + msg360472
2020-01-22 14:57:43serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg360471
2020-01-22 14:55:43serhiy.storchakasettype: crash
versions: + Python 3.7, Python 3.8
2020-01-21 08:57:41vstinnersetmessages: + msg360369
2020-01-21 08:53:51vstinnersetmessages: + msg360368
2020-01-20 12:18:52vstinnersetkeywords: + patch
stage: patch review
pull_requests: + pull_request17471
2020-01-20 11:58:54vstinnercreate