258 lines
9.3 KiB
Diff
258 lines
9.3 KiB
Diff
From 94083ce4d60abd390fbba615de333bdec07edc2c Mon Sep 17 00:00:00 2001
|
|
From: Pablo Galindo <Pablogsal@gmail.com>
|
|
Date: Mon, 29 Jan 2018 20:34:42 +0000
|
|
Subject: [PATCH] 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
|
|
|
|
Conflict:NA
|
|
Reference:https://github.com/python/cpython/commit/0cd6bca65519109a8a7862d38ba1b8924e432a16
|
|
|
|
Signed-off-by: hanxinke <hanxinke@huawei.com>
|
|
---
|
|
Modules/posixmodule.c | 111 +++++++++++++++++++++++++-----------------
|
|
1 file changed, 66 insertions(+), 45 deletions(-)
|
|
|
|
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
|
|
index fcb22c2..b5636f5 100644
|
|
--- a/Modules/posixmodule.c
|
|
+++ b/Modules/posixmodule.c
|
|
@@ -176,7 +176,6 @@ corresponding Unix manual entries for more information on calls.");
|
|
#else
|
|
/* Unix functions that the configure script doesn't check for */
|
|
#define HAVE_EXECV 1
|
|
-#define HAVE_POSIX_SPAWN 1
|
|
#define HAVE_FORK 1
|
|
#if defined(__USLC__) && defined(__SCO_VERSION__) /* SCO UDK Compiler */
|
|
#define HAVE_FORK1 1
|
|
@@ -5161,17 +5160,22 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
|
/*[clinic end generated code: output=d023521f541c709c input=0ec9f1cfdc890be5]*/
|
|
{
|
|
EXECV_CHAR **argvlist = NULL;
|
|
- EXECV_CHAR **envlist;
|
|
+ EXECV_CHAR **envlist = NULL;
|
|
+ posix_spawn_file_actions_t _file_actions;
|
|
+ posix_spawn_file_actions_t *file_actionsp = NULL;
|
|
Py_ssize_t argc, envc;
|
|
+ PyObject* result = NULL;
|
|
+ PyObject* seq = NULL;
|
|
+
|
|
|
|
/* posix_spawn has three arguments: (path, argv, env), where
|
|
argv is a list or tuple of strings and env is a dictionary
|
|
like posix.environ. */
|
|
|
|
- if (!PySequence_Check(argv)){
|
|
+ if (!PySequence_Check(argv)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"posix_spawn: argv must be a tuple or list");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
argc = PySequence_Size(argv);
|
|
if (argc < 1) {
|
|
@@ -5182,40 +5186,37 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
|
if (!PyMapping_Check(env)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"posix_spawn: environment must be a mapping object");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
argvlist = parse_arglist(argv, &argc);
|
|
if (argvlist == NULL) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
if (!argvlist[0][0]) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"posix_spawn: argv first element cannot be empty");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
envlist = parse_envlist(env, &envc);
|
|
- if (envlist == NULL)
|
|
- goto fail;
|
|
+ if (envlist == NULL) {
|
|
+ goto exit;
|
|
+ }
|
|
|
|
pid_t pid;
|
|
- posix_spawn_file_actions_t *file_actionsp = NULL;
|
|
- if (file_actions != NULL && file_actions != Py_None){
|
|
- posix_spawn_file_actions_t _file_actions;
|
|
+ if (file_actions != NULL && file_actions != Py_None) {
|
|
if(posix_spawn_file_actions_init(&_file_actions) != 0){
|
|
- PyErr_SetString(PyExc_TypeError,
|
|
+ PyErr_SetString(PyExc_OSError,
|
|
"Error initializing file actions");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
-
|
|
file_actionsp = &_file_actions;
|
|
|
|
-
|
|
- PyObject* seq = PySequence_Fast(file_actions, "file_actions must be a sequence");
|
|
- if(seq == NULL){
|
|
- goto fail;
|
|
+ seq = PySequence_Fast(file_actions, "file_actions must be a sequence");
|
|
+ if(seq == NULL) {
|
|
+ goto exit;
|
|
}
|
|
PyObject* file_actions_obj;
|
|
PyObject* mode_obj;
|
|
@@ -5223,9 +5224,9 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
|
for (int i = 0; i < PySequence_Fast_GET_SIZE(seq); ++i) {
|
|
file_actions_obj = PySequence_Fast_GET_ITEM(seq, i);
|
|
|
|
- if(!PySequence_Check(file_actions_obj) | !PySequence_Size(file_actions_obj)){
|
|
+ if(!PySequence_Check(file_actions_obj) | !PySequence_Size(file_actions_obj)) {
|
|
PyErr_SetString(PyExc_TypeError,"Each file_action element must be a non empty sequence");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
|
|
@@ -5237,83 +5238,103 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
|
|
switch(mode) {
|
|
|
|
case POSIX_SPAWN_OPEN:
|
|
- if(PySequence_Size(file_actions_obj) != 5){
|
|
+ if(PySequence_Size(file_actions_obj) != 5) {
|
|
PyErr_SetString(PyExc_TypeError,"A open file_action object must have 5 elements");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
long open_fd = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
const char* open_path = PyUnicode_AsUTF8(PySequence_GetItem(file_actions_obj, 2));
|
|
- if(open_path == NULL){
|
|
- goto fail;
|
|
+ if(open_path == NULL) {
|
|
+ goto exit;
|
|
}
|
|
long open_oflag = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 3));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
long open_mode = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 4));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
+ }
|
|
+ if(posix_spawn_file_actions_addopen(file_actionsp, open_fd, open_path, open_oflag, open_mode)) {
|
|
+ PyErr_SetString(PyExc_OSError,"Failed to add open file action");
|
|
+ goto exit;
|
|
}
|
|
- posix_spawn_file_actions_addopen(file_actionsp, open_fd, open_path, open_oflag, open_mode);
|
|
+
|
|
break;
|
|
|
|
case POSIX_SPAWN_CLOSE:
|
|
if(PySequence_Size(file_actions_obj) != 2){
|
|
PyErr_SetString(PyExc_TypeError,"A close file_action object must have 2 elements");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
long close_fd = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
+ }
|
|
+ if(posix_spawn_file_actions_addclose(file_actionsp, close_fd)) {
|
|
+ PyErr_SetString(PyExc_OSError,"Failed to add close file action");
|
|
+ goto exit;
|
|
}
|
|
- posix_spawn_file_actions_addclose(file_actionsp, close_fd);
|
|
break;
|
|
|
|
case POSIX_SPAWN_DUP2:
|
|
if(PySequence_Size(file_actions_obj) != 3){
|
|
PyErr_SetString(PyExc_TypeError,"A dup2 file_action object must have 3 elements");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
|
|
long fd1 = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 1));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
long fd2 = PyLong_AsLong(PySequence_GetItem(file_actions_obj, 2));
|
|
if(PyErr_Occurred()) {
|
|
- goto fail;
|
|
+ goto exit;
|
|
+ }
|
|
+ if(posix_spawn_file_actions_adddup2(file_actionsp, fd1, fd2)) {
|
|
+ PyErr_SetString(PyExc_OSError,"Failed to add dup2 file action");
|
|
+ goto exit;
|
|
}
|
|
- posix_spawn_file_actions_adddup2(file_actionsp, fd1, fd2);
|
|
break;
|
|
|
|
default:
|
|
PyErr_SetString(PyExc_TypeError,"Unknown file_actions identifier");
|
|
- goto fail;
|
|
+ goto exit;
|
|
}
|
|
}
|
|
- Py_DECREF(seq);
|
|
-}
|
|
+ }
|
|
|
|
_Py_BEGIN_SUPPRESS_IPH
|
|
- posix_spawn(&pid, path->narrow, file_actionsp, NULL, argvlist, envlist);
|
|
- return PyLong_FromPid(pid);
|
|
+ int err_code = posix_spawn(&pid, path->narrow, file_actionsp, NULL, argvlist, envlist);
|
|
_Py_END_SUPPRESS_IPH
|
|
+ if(err_code) {
|
|
+ PyErr_SetString(PyExc_OSError,"posix_spawn call failed");
|
|
+ goto exit;
|
|
+ }
|
|
+ result = PyLong_FromPid(pid);
|
|
|
|
- path_error(path);
|
|
+exit:
|
|
|
|
- free_string_array(envlist, envc);
|
|
+ Py_XDECREF(seq);
|
|
|
|
-fail:
|
|
+ if(file_actionsp) {
|
|
+ posix_spawn_file_actions_destroy(file_actionsp);
|
|
+ }
|
|
+
|
|
+ if (envlist) {
|
|
+ free_string_array(envlist, envc);
|
|
+ }
|
|
|
|
if (argvlist) {
|
|
free_string_array(argvlist, argc);
|
|
}
|
|
- return NULL;
|
|
+
|
|
+ return result;
|
|
|
|
|
|
}
|
|
--
|
|
2.23.0
|
|
|