Skip to content

Commit

Permalink
Fix SystemError exception when async_args PyTuple is reused. #1408
Browse files Browse the repository at this point in the history
In the case where the uwsgi_python_create_env_cheat env behavior is
used, the async_args PyTuple is reused on every request.

In some cases, the reference count on async_args may be > 1 at the end
of a request/response cycle. If PyTuple_SetItem is called with a
reference count > 1, a SystemError is raised.

When the cheat env behavior is used, the environ dictionary is also
reused between requests. This enables the elimination of redundant
PyTuple_SetItem calls by first checking to see if the environ dictionary
is already in the async_args tuple.
  • Loading branch information
a-feld authored and xrmx committed Dec 6, 2016
1 parent 199d2d5 commit 9ff7711
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 16 deletions.
7 changes: 6 additions & 1 deletion plugins/python/pump_subhandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,12 @@ void *uwsgi_request_subhandler_pump(struct wsgi_request *wsgi_req, struct uwsgi_

// call

PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ);
if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) {
if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) {
uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n");
return NULL;
}
}
return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req);
}

Expand Down
7 changes: 6 additions & 1 deletion plugins/python/web3_subhandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@ void *uwsgi_request_subhandler_web3(struct wsgi_request *wsgi_req, struct uwsgi_

// call

PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ);
if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) {
if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) {
uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n");
return NULL;
}
}
return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req);
}

Expand Down
20 changes: 6 additions & 14 deletions plugins/python/wsgi_subhandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,13 @@ void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_

PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.node", wi->uwsgi_node);

if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) {
// this is a hack cleaning up bad references when using the cheating allocator
// check https://github.com/unbit/uwsgi/issues/1408
PyObject *tmp_async_args = (PyObject *) wsgi_req->async_args;
if (tmp_async_args->ob_refcnt > 1) {
PyErr_Clear();
Py_DECREF(tmp_async_args);
if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) {
uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n");
return NULL;
}
}
}

// call
if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) {
if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) {
uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n");
return NULL;
}
}
return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req);
}

Expand Down

0 comments on commit 9ff7711

Please sign in to comment.