Skip to content

Commit 0cd6bca

Browse files
pablogsalgpshead
authored andcommitted
bpo-20104: Fix leaks and errors in new os.posix_spawn (GH-5418)
* Fix memory leaks and error handling in posix spawn * Improve error handling when destroying the file_actions object * Py_DECREF the result of PySequence_Fast on error * Handle uninitialized pid * Use OSError if file actions fails to initialize * Move _file_actions to outer scope to avoid undefined behaviour * Remove HAVE_POSIX_SPAWN define in Modules/posixmodule.c * Unshadow exception and clean error message
1 parent c65ef77 commit 0cd6bca

File tree

1 file changed

+66
-52
lines changed

1 file changed

+66
-52
lines changed

Modules/posixmodule.c

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,6 @@ corresponding Unix manual entries for more information on calls.");
176176
#else
177177
/* Unix functions that the configure script doesn't check for */
178178
#define HAVE_EXECV 1
179-
/* bpo-32705: Current Android does not have posix_spawn
180-
* Most likely posix_spawn will be available in next Android version (Android
181-
* P, API 28). Need revisit then. See
182-
* https://android-review.googlesource.com/c/platform/bionic/+/504842
183-
**/
184-
#ifndef __ANDROID__
185-
#define HAVE_POSIX_SPAWN 1
186-
#endif
187179
#define HAVE_FORK 1
188180
#if defined(__USLC__) && defined(__SCO_VERSION__) /* SCO UDK Compiler */
189181
#define HAVE_FORK1 1
@@ -5139,17 +5131,22 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
51395131
/*[clinic end generated code: output=d023521f541c709c input=0ec9f1cfdc890be5]*/
51405132
{
51415133
EXECV_CHAR **argvlist = NULL;
5142-
EXECV_CHAR **envlist;
5134+
EXECV_CHAR **envlist = NULL;
5135+
posix_spawn_file_actions_t _file_actions;
5136+
posix_spawn_file_actions_t *file_actionsp = NULL;
51435137
Py_ssize_t argc, envc;
5138+
PyObject* result = NULL;
5139+
PyObject* seq = NULL;
5140+
51445141

51455142
/* posix_spawn has three arguments: (path, argv, env), where
51465143
argv is a list or tuple of strings and env is a dictionary
51475144
like posix.environ. */
51485145

5149-
if (!PySequence_Check(argv)){
5146+
if (!PySequence_Check(argv)) {
51505147
PyErr_SetString(PyExc_TypeError,
51515148
"posix_spawn: argv must be a tuple or list");
5152-
goto fail;
5149+
goto exit;
51535150
}
51545151
argc = PySequence_Size(argv);
51555152
if (argc < 1) {
@@ -5160,50 +5157,47 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
51605157
if (!PyMapping_Check(env)) {
51615158
PyErr_SetString(PyExc_TypeError,
51625159
"posix_spawn: environment must be a mapping object");
5163-
goto fail;
5160+
goto exit;
51645161
}
51655162

51665163
argvlist = parse_arglist(argv, &argc);
51675164
if (argvlist == NULL) {
5168-
goto fail;
5165+
goto exit;
51695166
}
51705167
if (!argvlist[0][0]) {
51715168
PyErr_SetString(PyExc_ValueError,
51725169
"posix_spawn: argv first element cannot be empty");
5173-
goto fail;
5170+
goto exit;
51745171
}
51755172

51765173
envlist = parse_envlist(env, &envc);
5177-
if (envlist == NULL)
5178-
goto fail;
5174+
if (envlist == NULL) {
5175+
goto exit;
5176+
}
51795177

51805178
pid_t pid;
5181-
posix_spawn_file_actions_t *file_actionsp = NULL;
5182-
if (file_actions != NULL && file_actions != Py_None){
5183-
posix_spawn_file_actions_t _file_actions;
5179+
if (file_actions != NULL && file_actions != Py_None) {
51845180
if(posix_spawn_file_actions_init(&_file_actions) != 0){
5185-
PyErr_SetString(PyExc_TypeError,
5181+
PyErr_SetString(PyExc_OSError,
51865182
"Error initializing file actions");
5187-
goto fail;
5183+
goto exit;
51885184
}
51895185

5190-
51915186
file_actionsp = &_file_actions;
51925187

5193-
5194-
PyObject* seq = PySequence_Fast(file_actions, "file_actions must be a sequence");
5195-
if(seq == NULL){
5196-
goto fail;
5188+
seq = PySequence_Fast(file_actions, "file_actions must be a sequence");
5189+
if(seq == NULL) {
5190+
goto exit;
51975191
}
51985192
PyObject* file_actions_obj;
51995193
PyObject* mode_obj;
52005194

52015195
for (int i = 0; i < PySequence_Fast_GET_SIZE(seq); ++i) {
52025196
file_actions_obj = PySequence_Fast_GET_ITEM(seq, i);
52035197

5204-
if(!PySequence_Check(file_actions_obj) | !PySequence_Size(file_actions_obj)){
5198+
if(!PySequence_Check(file_actions_obj) | !PySequence_Size(file_actions_obj)) {
52055199
PyErr_SetString(PyExc_TypeError,"Each file_action element must be a non empty sequence");
5206-
goto fail;
5200+
goto exit;
52075201
}
52085202

52095203

@@ -5215,83 +5209,103 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
52155209
switch(mode) {
52165210

52175211
case POSIX_SPAWN_OPEN:
5218-
if(PySequence_Size(file_actions_obj) != 5){
5212+
if(PySequence_Size(file_actions_obj) != 5) {
52195213
PyErr_SetString(PyExc_TypeError,"A open file_action object must have 5 elements");
5220-
goto fail;
5214+
goto exit;
52215215
}
52225216

52235217
long open_fd = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
52245218
if(PyErr_Occurred()) {
5225-
goto fail;
5219+
goto exit;
52265220
}
52275221
const char* open_path = PyUnicode_AsUTF8(PySequence_GetItem(file_actions_obj, 2));
5228-
if(open_path == NULL){
5229-
goto fail;
5222+
if(open_path == NULL) {
5223+
goto exit;
52305224
}
52315225
long open_oflag = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 3));
52325226
if(PyErr_Occurred()) {
5233-
goto fail;
5227+
goto exit;
52345228
}
52355229
long open_mode = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 4));
52365230
if(PyErr_Occurred()) {
5237-
goto fail;
5231+
goto exit;
5232+
}
5233+
if(posix_spawn_file_actions_addopen(file_actionsp, open_fd, open_path, open_oflag, open_mode)) {
5234+
PyErr_SetString(PyExc_OSError,"Failed to add open file action");
5235+
goto exit;
52385236
}
5239-
posix_spawn_file_actions_addopen(file_actionsp, open_fd, open_path, open_oflag, open_mode);
5237+
52405238
break;
52415239

52425240
case POSIX_SPAWN_CLOSE:
52435241
if(PySequence_Size(file_actions_obj) != 2){
52445242
PyErr_SetString(PyExc_TypeError,"A close file_action object must have 2 elements");
5245-
goto fail;
5243+
goto exit;
52465244
}
52475245

52485246
long close_fd = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
52495247
if(PyErr_Occurred()) {
5250-
goto fail;
5248+
goto exit;
5249+
}
5250+
if(posix_spawn_file_actions_addclose(file_actionsp, close_fd)) {
5251+
PyErr_SetString(PyExc_OSError,"Failed to add close file action");
5252+
goto exit;
52515253
}
5252-
posix_spawn_file_actions_addclose(file_actionsp, close_fd);
52535254
break;
52545255

52555256
case POSIX_SPAWN_DUP2:
52565257
if(PySequence_Size(file_actions_obj) != 3){
52575258
PyErr_SetString(PyExc_TypeError,"A dup2 file_action object must have 3 elements");
5258-
goto fail;
5259+
goto exit;
52595260
}
52605261

52615262
long fd1 = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
52625263
if(PyErr_Occurred()) {
5263-
goto fail;
5264+
goto exit;
52645265
}
52655266
long fd2 = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 2));
52665267
if(PyErr_Occurred()) {
5267-
goto fail;
5268+
goto exit;
5269+
}
5270+
if(posix_spawn_file_actions_adddup2(file_actionsp, fd1, fd2)) {
5271+
PyErr_SetString(PyExc_OSError,"Failed to add dup2 file action");
5272+
goto exit;
52685273
}
5269-
posix_spawn_file_actions_adddup2(file_actionsp, fd1, fd2);
52705274
break;
52715275

52725276
default:
52735277
PyErr_SetString(PyExc_TypeError,"Unknown file_actions identifier");
5274-
goto fail;
5278+
goto exit;
52755279
}
52765280
}
5277-
Py_DECREF(seq);
5278-
}
5281+
}
52795282

52805283
_Py_BEGIN_SUPPRESS_IPH
5281-
posix_spawn(&pid, path->narrow, file_actionsp, NULL, argvlist, envlist);
5282-
return PyLong_FromPid(pid);
5284+
int err_code = posix_spawn(&pid, path->narrow, file_actionsp, NULL, argvlist, envlist);
52835285
_Py_END_SUPPRESS_IPH
5286+
if(err_code) {
5287+
PyErr_SetString(PyExc_OSError,"posix_spawn call failed");
5288+
goto exit;
5289+
}
5290+
result = PyLong_FromPid(pid);
52845291

5285-
path_error(path);
5292+
exit:
52865293

5287-
free_string_array(envlist, envc);
5294+
Py_XDECREF(seq);
52885295

5289-
fail:
5296+
if(file_actionsp) {
5297+
posix_spawn_file_actions_destroy(file_actionsp);
5298+
}
5299+
5300+
if (envlist) {
5301+
free_string_array(envlist, envc);
5302+
}
52905303

52915304
if (argvlist) {
52925305
free_string_array(argvlist, argc);
52935306
}
5294-
return NULL;
5307+
5308+
return result;
52955309

52965310

52975311
}

0 commit comments

Comments
 (0)