-
-
Notifications
You must be signed in to change notification settings - Fork 32k
bpo-33625: Release GIL for grp.getgr{nam,gid} and pwd.getpw{nam,uid} #7081
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
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
454bc0c
Release GIL for `grp` and `pwd` single methods.
william-gr e9a92f1
Address @serhiy-storchaka review
william-gr dcc6af6
Address @serhiy-storchaka and @vstinner reviews
william-gr 491f1f8
Address @serhiy-storchaka review
william-gr 5cccd68
Use PyErr_NoMemory()
william-gr 649fb60
Use while instead of do as advised
william-gr e59d2c1
GIL is not always released, reword NEWS entry.
william-gr 874339e
Address reviews from @vstinner
william-gr b02311e
Move Realloc and remove Malloc so we always check if it succeeded
william-gr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
Misc/NEWS.d/next/Library/2018-05-23-17-07-54.bpo-33625.nzQgD8.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Release GIL on `grp.getgrnam`, `grp.getgrgid`, `pwd.getpwnam` and | ||
`pwd.getpwuid` if reentrant variants of these functions are available. | ||
Patch by William Grzybowski. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,8 @@ exception is raised if the entry asked for cannot be found."); | |
static int initialized; | ||
static PyTypeObject StructPwdType; | ||
|
||
#define DEFAULT_BUFFER_SIZE 1024 | ||
|
||
static void | ||
sets(PyObject *v, int i, const char* val) | ||
{ | ||
|
@@ -116,16 +118,59 @@ static PyObject * | |
pwd_getpwuid(PyObject *module, PyObject *uidobj) | ||
/*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/ | ||
{ | ||
PyObject *retval = NULL; | ||
uid_t uid; | ||
int nomem = 0; | ||
struct passwd *p; | ||
char *buf = NULL, *buf2 = NULL; | ||
|
||
if (!_Py_Uid_Converter(uidobj, &uid)) { | ||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) | ||
PyErr_Format(PyExc_KeyError, | ||
"getpwuid(): uid not found"); | ||
return NULL; | ||
} | ||
if ((p = getpwuid(uid)) == NULL) { | ||
#ifdef HAVE_GETPWUID_R | ||
Py_BEGIN_ALLOW_THREADS | ||
int status; | ||
Py_ssize_t bufsize; | ||
struct passwd pwd; | ||
|
||
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); | ||
if (bufsize == -1) { | ||
bufsize = DEFAULT_BUFFER_SIZE; | ||
} | ||
|
||
while(1) { | ||
buf2 = PyMem_RawRealloc(buf, bufsize); | ||
if (buf2 == NULL) { | ||
nomem = 1; | ||
break; | ||
} | ||
buf = buf2; | ||
status = getpwuid_r(uid, &pwd, buf, bufsize, &p); | ||
if (status != 0) { | ||
p = NULL; | ||
} | ||
if (p != NULL || status != ERANGE) { | ||
break; | ||
} | ||
if (bufsize > (PY_SSIZE_T_MAX >> 1)) { | ||
nomem = 1; | ||
break; | ||
} | ||
bufsize <<= 1; | ||
} | ||
|
||
Py_END_ALLOW_THREADS | ||
#else | ||
p = getpwuid(uid); | ||
#endif | ||
if (p == NULL) { | ||
PyMem_RawFree(buf); | ||
if (nomem == 1) { | ||
return PyErr_NoMemory(); | ||
} | ||
PyObject *uid_obj = _PyLong_FromUid(uid); | ||
if (uid_obj == NULL) | ||
return NULL; | ||
|
@@ -134,7 +179,11 @@ pwd_getpwuid(PyObject *module, PyObject *uidobj) | |
Py_DECREF(uid_obj); | ||
return NULL; | ||
} | ||
return mkpwent(p); | ||
retval = mkpwent(p); | ||
#ifdef HAVE_GETPWUID_R | ||
PyMem_RawFree(buf); | ||
#endif | ||
return retval; | ||
} | ||
|
||
/*[clinic input] | ||
|
@@ -152,7 +201,8 @@ static PyObject * | |
pwd_getpwnam_impl(PyObject *module, PyObject *arg) | ||
/*[clinic end generated code: output=6abeee92430e43d2 input=d5f7e700919b02d3]*/ | ||
{ | ||
char *name; | ||
char *buf = NULL, *buf2 = NULL, *name; | ||
int nomem = 0; | ||
struct passwd *p; | ||
PyObject *bytes, *retval = NULL; | ||
|
||
|
@@ -161,13 +211,55 @@ pwd_getpwnam_impl(PyObject *module, PyObject *arg) | |
/* check for embedded null bytes */ | ||
if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1) | ||
goto out; | ||
if ((p = getpwnam(name)) == NULL) { | ||
PyErr_Format(PyExc_KeyError, | ||
"getpwnam(): name not found: %s", name); | ||
#ifdef HAVE_GETPWNAM_R | ||
Py_BEGIN_ALLOW_THREADS | ||
int status; | ||
Py_ssize_t bufsize; | ||
struct passwd pwd; | ||
|
||
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); | ||
if (bufsize == -1) { | ||
bufsize = DEFAULT_BUFFER_SIZE; | ||
} | ||
|
||
while(1) { | ||
buf2 = PyMem_RawRealloc(buf, bufsize); | ||
if (buf2 == NULL) { | ||
nomem = 1; | ||
break; | ||
} | ||
buf = buf2; | ||
status = getpwnam_r(name, &pwd, buf, bufsize, &p); | ||
if (status != 0) { | ||
p = NULL; | ||
} | ||
if (p != NULL || status != ERANGE) { | ||
break; | ||
} | ||
if (bufsize > (PY_SSIZE_T_MAX >> 1)) { | ||
nomem = 1; | ||
break; | ||
} | ||
bufsize <<= 1; | ||
} | ||
|
||
Py_END_ALLOW_THREADS | ||
#else | ||
p = getpwnam(name); | ||
#endif | ||
if (p == NULL) { | ||
if (nomem == 1) { | ||
PyErr_NoMemory(); | ||
} | ||
else { | ||
PyErr_Format(PyExc_KeyError, | ||
"getpwnam(): name not found: %s", name); | ||
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. Same comment: please use the %S format here, but if you modify this function, would you mind to also fix the name of the parameter? Rename "arg" to "name", as in Doc/library/pwd.rst. Maybe rename the char* name to name_chars, as in grp_getgrnam_impl(). |
||
} | ||
goto out; | ||
} | ||
retval = mkpwent(p); | ||
out: | ||
PyMem_RawFree(buf); | ||
Py_DECREF(bytes); | ||
return retval; | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Hum, I see a bug which is not related to your change, but while we modify these functions, it would be nice to fix it.
name_chars is encoded to the filesystem encoding, whereas %s decodes it from UTF-8. If the filesystem encoding is not UTF-8, you get mojibake.
The fix is simple: use %S format and pass name: name is always a Unicode string.
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.
If name is always a Unicode string, you can use %U.
It may be worth to use %R for the case if the name contains invisible characters or trailing whitespaces.
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.
See https://bugs.python.org/issue34604 :-)