Skip to content

Commit 3db7086

Browse files
awelzelFran6nd
authored andcommitted
python: use consistent key type for opt dict manipulations - fixes unbit#1374
PyString_FromString is defined as PyBytes_FromString in uwsgi_python.h What happens in Python 3 during the population of the opt_dict is that we first check if a byte object, representing the key is in the dict. If there is none, we use PyDict_SetItemString to set it. However, as the docs say, PyDict_SetItemString will convert the key using PyUnicode_FromString and we actually put a unicode key in the dict[1]. Therefore, when we check the "same" key again, we check again for the "same" key as bytes object we don't find it and end up overwriting it instead of doing the list promotion dance. Attached patch fixes this by using PyDict_SetItem and PyDict_GetItem with a consistent key type. For Python 3, a unicode object is used as key as this is the backwards compatible thing to do. Mini tester: import uwsgi def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) for k, v in uwsgi.opt.items(): yield "{} {!r} ({})\n".format(k, v, type(v)).encode("utf-8") yield "{} {}\n".format(uwsgi.version, type(uwsgi.version)).encode("utf-8") yield "{} {}\n".format(uwsgi.hostname, type(uwsgi.hostname)).encode("utf-8") yield b"END" What is a bit rough is that in Python 3 the actual values for uwsgi.opt entries end-up being all bytes, but that has always been like this... [1] https://docs.python.org/3.5/c-api/dict.html#c.PyDict_SetItemString
1 parent 76e58db commit 3db7086

File tree

1 file changed

+10
-5
lines changed

1 file changed

+10
-5
lines changed

plugins/python/python_plugin.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,13 @@ void init_uwsgi_embedded_module() {
819819

820820
PyObject *py_opt_dict = PyDict_New();
821821
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
822-
if (PyDict_Contains(py_opt_dict, PyString_FromString(uwsgi.exported_opts[i]->key))) {
823-
PyObject *py_opt_item = PyDict_GetItemString(py_opt_dict, uwsgi.exported_opts[i]->key);
822+
#ifdef PYTHREE
823+
PyObject *key = PyUnicode_FromString(uwsgi.exported_opts[i]->key);
824+
#else
825+
PyObject *key = PyString_FromString(uwsgi.exported_opts[i]->key);
826+
#endif
827+
if (PyDict_Contains(py_opt_dict, key)) {
828+
PyObject *py_opt_item = PyDict_GetItem(py_opt_dict, key);
824829
if (PyList_Check(py_opt_item)) {
825830
if (uwsgi.exported_opts[i]->value == NULL) {
826831
PyList_Append(py_opt_item, Py_True);
@@ -839,15 +844,15 @@ void init_uwsgi_embedded_module() {
839844
PyList_Append(py_opt_list, PyString_FromString(uwsgi.exported_opts[i]->value));
840845
}
841846

842-
PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, py_opt_list);
847+
PyDict_SetItem(py_opt_dict, key, py_opt_list);
843848
}
844849
}
845850
else {
846851
if (uwsgi.exported_opts[i]->value == NULL) {
847-
PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, Py_True);
852+
PyDict_SetItem(py_opt_dict, key, Py_True);
848853
}
849854
else {
850-
PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, PyString_FromString(uwsgi.exported_opts[i]->value));
855+
PyDict_SetItem(py_opt_dict, key, PyString_FromString(uwsgi.exported_opts[i]->value));
851856
}
852857
}
853858
}

0 commit comments

Comments
 (0)