Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5ddd4c3

Browse files
committed
Fixed SF bug #663074. The codec system was using global static
variables to store internal data. As a result, any atempts to use the unicode system with multiple active interpreters, or successive interpreter executions, would fail. Now that information is stored into members of the PyInterpreterState structure.
1 parent 821a0fc commit 5ddd4c3

5 files changed

Lines changed: 80 additions & 92 deletions

File tree

Include/pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ typedef struct _is {
2222
PyObject *sysdict;
2323
PyObject *builtins;
2424

25+
PyObject *codec_search_path;
26+
PyObject *codec_search_cache;
27+
PyObject *codec_error_registry;
28+
2529
#ifdef HAVE_DLOPEN
2630
int dlopenflags;
2731
#endif

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ Core and builtins
2929
- On 64-bit systems, a dictionary could contain duplicate long/int keys
3030
if the key value was larger than 2**32. See SF bug #689659.
3131

32+
- Fixed SF bug #663074. The codec system was using global static
33+
variables to store internal data. As a result, any atempts to use the
34+
unicode system with multiple active interpreters, or successive
35+
interpreter executions, would fail.
36+
3237
Extension modules
3338
-----------------
3439

Python/codecs.c

Lines changed: 65 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,6 @@ Copyright (c) Corporation for National Research Initiatives.
1111
#include "Python.h"
1212
#include <ctype.h>
1313

14-
/* --- Globals ------------------------------------------------------------ */
15-
16-
static PyObject *_PyCodec_SearchPath;
17-
static PyObject *_PyCodec_SearchCache;
18-
19-
/* Flag used for lazy import of the standard encodings package */
20-
static int import_encodings_called = 0;
21-
2214
/* --- Codec Registry ----------------------------------------------------- */
2315

2416
/* Import the standard encodings package which will register the first
@@ -32,35 +24,13 @@ static int import_encodings_called = 0;
3224
3325
*/
3426

35-
static
36-
int import_encodings(void)
37-
{
38-
PyObject *mod;
39-
40-
import_encodings_called = 1;
41-
mod = PyImport_ImportModuleEx("encodings", NULL, NULL, NULL);
42-
if (mod == NULL) {
43-
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
44-
/* Ignore ImportErrors... this is done so that
45-
distributions can disable the encodings package. Note
46-
that other errors are not masked, e.g. SystemErrors
47-
raised to inform the user of an error in the Python
48-
configuration are still reported back to the user. */
49-
PyErr_Clear();
50-
return 0;
51-
}
52-
return -1;
53-
}
54-
Py_DECREF(mod);
55-
return 0;
56-
}
27+
static int _PyCodecRegistry_Init(void); /* Forward */
5728

5829
int PyCodec_Register(PyObject *search_function)
5930
{
60-
if (!import_encodings_called) {
61-
if (import_encodings())
62-
goto onError;
63-
}
31+
PyInterpreterState *interp = PyThreadState_Get()->interp;
32+
if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
33+
goto onError;
6434
if (search_function == NULL) {
6535
PyErr_BadArgument();
6636
goto onError;
@@ -70,7 +40,7 @@ int PyCodec_Register(PyObject *search_function)
7040
"argument must be callable");
7141
goto onError;
7242
}
73-
return PyList_Append(_PyCodec_SearchPath, search_function);
43+
return PyList_Append(interp->codec_search_path, search_function);
7444

7545
onError:
7646
return -1;
@@ -124,23 +94,18 @@ PyObject *normalizestring(const char *string)
12494

12595
PyObject *_PyCodec_Lookup(const char *encoding)
12696
{
97+
PyInterpreterState *interp;
12798
PyObject *result, *args = NULL, *v;
12899
int i, len;
129100

130101
if (encoding == NULL) {
131102
PyErr_BadArgument();
132103
goto onError;
133104
}
134-
if (_PyCodec_SearchCache == NULL ||
135-
_PyCodec_SearchPath == NULL) {
136-
PyErr_SetString(PyExc_SystemError,
137-
"codec module not properly initialized");
105+
106+
interp = PyThreadState_Get()->interp;
107+
if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
138108
goto onError;
139-
}
140-
if (!import_encodings_called) {
141-
if (import_encodings())
142-
goto onError;
143-
}
144109

145110
/* Convert the encoding to a normalized Python string: all
146111
characters are converted to lower case, spaces and hyphens are
@@ -151,7 +116,7 @@ PyObject *_PyCodec_Lookup(const char *encoding)
151116
PyString_InternInPlace(&v);
152117

153118
/* First, try to lookup the name in the registry dictionary */
154-
result = PyDict_GetItem(_PyCodec_SearchCache, v);
119+
result = PyDict_GetItem(interp->codec_search_cache, v);
155120
if (result != NULL) {
156121
Py_INCREF(result);
157122
Py_DECREF(v);
@@ -164,7 +129,7 @@ PyObject *_PyCodec_Lookup(const char *encoding)
164129
goto onError;
165130
PyTuple_SET_ITEM(args,0,v);
166131

167-
len = PyList_Size(_PyCodec_SearchPath);
132+
len = PyList_Size(interp->codec_search_path);
168133
if (len < 0)
169134
goto onError;
170135
if (len == 0) {
@@ -177,7 +142,7 @@ PyObject *_PyCodec_Lookup(const char *encoding)
177142
for (i = 0; i < len; i++) {
178143
PyObject *func;
179144

180-
func = PyList_GetItem(_PyCodec_SearchPath, i);
145+
func = PyList_GetItem(interp->codec_search_path, i);
181146
if (func == NULL)
182147
goto onError;
183148
result = PyEval_CallObject(func, args);
@@ -203,7 +168,7 @@ PyObject *_PyCodec_Lookup(const char *encoding)
203168
}
204169

205170
/* Cache and return the result */
206-
PyDict_SetItem(_PyCodec_SearchCache, v, result);
171+
PyDict_SetItem(interp->codec_search_cache, v, result);
207172
Py_DECREF(args);
208173
return result;
209174

@@ -422,8 +387,6 @@ PyObject *PyCodec_Decode(PyObject *object,
422387
return NULL;
423388
}
424389

425-
static PyObject *_PyCodec_ErrorRegistry;
426-
427390
/* Register the error handling callback function error under the name
428391
name. This function will be called by the codec when it encounters
429392
an unencodable characters/undecodable bytes and doesn't know the
@@ -432,11 +395,15 @@ static PyObject *_PyCodec_ErrorRegistry;
432395
Return 0 on success, -1 on error */
433396
int PyCodec_RegisterError(const char *name, PyObject *error)
434397
{
398+
PyInterpreterState *interp = PyThreadState_Get()->interp;
399+
if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
400+
return -1;
435401
if (!PyCallable_Check(error)) {
436402
PyErr_SetString(PyExc_TypeError, "handler must be callable");
437403
return -1;
438404
}
439-
return PyDict_SetItemString( _PyCodec_ErrorRegistry, (char *)name, error);
405+
return PyDict_SetItemString(interp->codec_error_registry,
406+
(char *)name, error);
440407
}
441408

442409
/* Lookup the error handling callback function registered under the
@@ -446,9 +413,13 @@ PyObject *PyCodec_LookupError(const char *name)
446413
{
447414
PyObject *handler = NULL;
448415

416+
PyInterpreterState *interp = PyThreadState_Get()->interp;
417+
if (interp->codec_search_path == NULL && _PyCodecRegistry_Init())
418+
return NULL;
419+
449420
if (name==NULL)
450421
name = "strict";
451-
handler = PyDict_GetItemString(_PyCodec_ErrorRegistry, (char *)name);
422+
handler = PyDict_GetItemString(interp->codec_error_registry, (char *)name);
452423
if (!handler)
453424
PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name);
454425
else
@@ -762,8 +733,7 @@ static PyObject *backslashreplace_errors(PyObject *self, PyObject *exc)
762733
}
763734
#endif
764735

765-
766-
void _PyCodecRegistry_Init(void)
736+
static int _PyCodecRegistry_Init(void)
767737
{
768738
static struct {
769739
char *name;
@@ -813,38 +783,49 @@ void _PyCodecRegistry_Init(void)
813783
}
814784
#endif
815785
};
816-
if (_PyCodec_SearchPath == NULL)
817-
_PyCodec_SearchPath = PyList_New(0);
818-
if (_PyCodec_SearchCache == NULL)
819-
_PyCodec_SearchCache = PyDict_New();
820-
if (_PyCodec_ErrorRegistry == NULL) {
821-
int i;
822-
_PyCodec_ErrorRegistry = PyDict_New();
823-
824-
if (_PyCodec_ErrorRegistry) {
825-
for (i = 0; i < sizeof(methods)/sizeof(methods[0]); ++i) {
826-
PyObject *func = PyCFunction_New(&methods[i].def, NULL);
827-
int res;
828-
if (!func)
829-
Py_FatalError("can't initialize codec error registry");
830-
res = PyCodec_RegisterError(methods[i].name, func);
831-
Py_DECREF(func);
832-
if (res)
833-
Py_FatalError("can't initialize codec error registry");
834-
}
786+
787+
PyInterpreterState *interp = PyThreadState_Get()->interp;
788+
PyObject *mod;
789+
int i;
790+
791+
if (interp->codec_search_path != NULL)
792+
return 0;
793+
794+
interp->codec_search_path = PyList_New(0);
795+
interp->codec_search_cache = PyDict_New();
796+
interp->codec_error_registry = PyDict_New();
797+
798+
if (interp->codec_error_registry) {
799+
for (i = 0; i < sizeof(methods)/sizeof(methods[0]); ++i) {
800+
PyObject *func = PyCFunction_New(&methods[i].def, NULL);
801+
int res;
802+
if (!func)
803+
Py_FatalError("can't initialize codec error registry");
804+
res = PyCodec_RegisterError(methods[i].name, func);
805+
Py_DECREF(func);
806+
if (res)
807+
Py_FatalError("can't initialize codec error registry");
835808
}
836809
}
837-
if (_PyCodec_SearchPath == NULL ||
838-
_PyCodec_SearchCache == NULL)
810+
811+
if (interp->codec_search_path == NULL ||
812+
interp->codec_search_cache == NULL ||
813+
interp->codec_error_registry == NULL)
839814
Py_FatalError("can't initialize codec registry");
840-
}
841815

842-
void _PyCodecRegistry_Fini(void)
843-
{
844-
Py_XDECREF(_PyCodec_SearchPath);
845-
_PyCodec_SearchPath = NULL;
846-
Py_XDECREF(_PyCodec_SearchCache);
847-
_PyCodec_SearchCache = NULL;
848-
Py_XDECREF(_PyCodec_ErrorRegistry);
849-
_PyCodec_ErrorRegistry = NULL;
816+
mod = PyImport_ImportModuleEx("encodings", NULL, NULL, NULL);
817+
if (mod == NULL) {
818+
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
819+
/* Ignore ImportErrors... this is done so that
820+
distributions can disable the encodings package. Note
821+
that other errors are not masked, e.g. SystemErrors
822+
raised to inform the user of an error in the Python
823+
configuration are still reported back to the user. */
824+
PyErr_Clear();
825+
return 0;
826+
}
827+
return -1;
828+
}
829+
Py_DECREF(mod);
830+
return 0;
850831
}

Python/pystate.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ PyInterpreterState_New(void)
4949
interp->sysdict = NULL;
5050
interp->builtins = NULL;
5151
interp->tstate_head = NULL;
52+
interp->codec_search_path = NULL;
53+
interp->codec_search_cache = NULL;
54+
interp->codec_error_registry = NULL;
5255
#ifdef HAVE_DLOPEN
5356
#ifdef RTLD_NOW
5457
interp->dlopenflags = RTLD_NOW;
@@ -75,6 +78,9 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
7578
for (p = interp->tstate_head; p != NULL; p = p->next)
7679
PyThreadState_Clear(p);
7780
HEAD_UNLOCK();
81+
ZAP(interp->codec_search_path);
82+
ZAP(interp->codec_search_cache);
83+
ZAP(interp->codec_error_registry);
7884
ZAP(interp->modules);
7985
ZAP(interp->sysdict);
8086
ZAP(interp->builtins);

Python/pythonrun.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ static void call_sys_exitfunc(void);
4949
static void call_ll_exitfuncs(void);
5050
extern void _PyUnicode_Init(void);
5151
extern void _PyUnicode_Fini(void);
52-
extern void _PyCodecRegistry_Init(void);
53-
extern void _PyCodecRegistry_Fini(void);
5452

5553
int Py_DebugFlag; /* Needed by parser.c */
5654
int Py_VerboseFlag; /* Needed by import.c */
@@ -144,9 +142,6 @@ Py_Initialize(void)
144142
if (interp->modules == NULL)
145143
Py_FatalError("Py_Initialize: can't make modules dictionary");
146144

147-
/* Init codec registry */
148-
_PyCodecRegistry_Init();
149-
150145
#ifdef Py_USING_UNICODE
151146
/* Init Unicode implementation; relies on the codec registry */
152147
_PyUnicode_Init();
@@ -257,9 +252,6 @@ Py_Finalize(void)
257252
/* Disable signal handling */
258253
PyOS_FiniInterrupts();
259254

260-
/* Cleanup Codec registry */
261-
_PyCodecRegistry_Fini();
262-
263255
/* drop module references we saved */
264256
Py_XDECREF(PyModule_WarningsModule);
265257
PyModule_WarningsModule = NULL;

0 commit comments

Comments
 (0)