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

Skip to content

Commit 5b22213

Browse files
committed
Make identifiers str (not str8) objects throughout.
This affects the parser, various object implementations, and all places that put identifiers into C string literals. In testing, a number of crashes occurred as code would fail when the recursion limit was reached (such as the Unicode interning dictionary having key/value pairs where key is not value). To solve these, I added an overflowed flag, which allows for 50 more recursions after the limit was reached and the exception was raised, and a recursion_critical flag, which indicates that recursion absolutely must be allowed, i.e. that a certain call must not cause a stack overflow exception. There are still some places where both str and str8 are accepted as identifiers; these should eventually be removed.
1 parent 38e43c2 commit 5b22213

40 files changed

Lines changed: 462 additions & 289 deletions

Include/ceval.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ PyAPI_FUNC(int) Py_GetRecursionLimit(void);
5050
(_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \
5151
_Py_CheckRecursiveCall(where))
5252
#define Py_LeaveRecursiveCall() \
53-
(--PyThreadState_GET()->recursion_depth)
53+
do{ if((--PyThreadState_GET()->recursion_depth) < \
54+
_Py_CheckRecursionLimit - 50); \
55+
PyThreadState_GET()->overflowed = 0; \
56+
} while(0)
5457
PyAPI_FUNC(int) _Py_CheckRecursiveCall(char *where);
5558
PyAPI_DATA(int) _Py_CheckRecursionLimit;
5659
#ifdef USE_STACKCHECK
@@ -59,6 +62,14 @@ PyAPI_DATA(int) _Py_CheckRecursionLimit;
5962
# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit)
6063
#endif
6164

65+
#define Py_ALLOW_RECURSION \
66+
do { unsigned char _old = PyThreadState_GET()->recursion_critical;\
67+
PyThreadState_GET()->recursion_critical = 1;
68+
69+
#define Py_END_ALLOW_RECURSION \
70+
PyThreadState_GET()->recursion_critical = _old; \
71+
} while(0);
72+
6273
PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *);
6374
PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *);
6475

Include/pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ typedef struct _ts {
6161

6262
struct _frame *frame;
6363
int recursion_depth;
64+
char overflowed; /* The stack has overflowed. Allow 50 more calls
65+
to handle the runtime error. */
66+
char recursion_critical; /* The current calls must not cause
67+
a stack overflow. */
6468
/* 'tracing' keeps track of the execution depth when tracing/profiling.
6569
This is to prevent the actual trace/profile code from being recorded in
6670
the trace/profile. */

Include/stringobject.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ PyAPI_FUNC(void) _Py_ReleaseInternedStrings(void);
8484
#define PyString_CHECK_INTERNED(op) (((PyStringObject *)(op))->ob_sstate)
8585

8686
/* Macro, trading safety for speed */
87-
#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
88-
#define PyString_GET_SIZE(op) (((PyStringObject *)(op))->ob_size)
87+
#define PyString_AS_STRING(op) (assert(PyString_Check(op)),(((PyStringObject *)(op))->ob_sval))
88+
#define PyString_GET_SIZE(op) (assert(PyString_Check(op)),(((PyStringObject *)(op))->ob_size))
8989

9090
/* _PyString_Join(sep, x) is like sep.join(x). sep must be PyStringObject*,
9191
x must be an iterable object. */

Include/unicodeobject.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,13 +410,13 @@ PyAPI_DATA(PyTypeObject) PyUnicode_Type;
410410

411411
/* Fast access macros */
412412
#define PyUnicode_GET_SIZE(op) \
413-
(((PyUnicodeObject *)(op))->length)
413+
(assert(PyUnicode_Check(op)),(((PyUnicodeObject *)(op))->length))
414414
#define PyUnicode_GET_DATA_SIZE(op) \
415-
(((PyUnicodeObject *)(op))->length * sizeof(Py_UNICODE))
415+
(assert(PyUnicode_Check(op)),(((PyUnicodeObject *)(op))->length * sizeof(Py_UNICODE)))
416416
#define PyUnicode_AS_UNICODE(op) \
417-
(((PyUnicodeObject *)(op))->str)
417+
(assert(PyUnicode_Check(op)),(((PyUnicodeObject *)(op))->str))
418418
#define PyUnicode_AS_DATA(op) \
419-
((const char *)((PyUnicodeObject *)(op))->str)
419+
(assert(PyUnicode_Check(op)),((const char *)((PyUnicodeObject *)(op))->str))
420420

421421
/* --- Constants ---------------------------------------------------------- */
422422

@@ -627,6 +627,13 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromOrdinal(int ordinal);
627627
PyAPI_FUNC(PyObject *) _PyUnicode_AsDefaultEncodedString(
628628
PyObject *, const char *);
629629

630+
/* Return a char* holding the default encoded value of the
631+
Unicode object.
632+
*/
633+
634+
PyAPI_FUNC(char *) PyUnicode_AsString(PyObject*);
635+
636+
630637
/* Returns the currently active default encoding.
631638
632639
The default encoding is currently implemented as run-time settable
@@ -1193,6 +1200,11 @@ PyAPI_FUNC(int) PyUnicode_Compare(
11931200
PyObject *right /* Right string */
11941201
);
11951202

1203+
PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString(
1204+
PyObject *left,
1205+
const char *right
1206+
);
1207+
11961208
/* Rich compare two strings and return one of the following:
11971209
11981210
- NULL in case an exception was raised
@@ -1310,6 +1322,22 @@ PyAPI_FUNC(int) _PyUnicode_IsAlpha(
13101322
Py_UNICODE ch /* Unicode character */
13111323
);
13121324

1325+
PyAPI_FUNC(size_t) Py_UNICODE_strlen(const Py_UNICODE *u);
1326+
1327+
PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcpy(
1328+
Py_UNICODE *s1, const Py_UNICODE *s2);
1329+
1330+
PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strncpy(
1331+
Py_UNICODE *s1, const Py_UNICODE *s2, size_t n);
1332+
1333+
PyAPI_FUNC(int) Py_UNICODE_strcmp(
1334+
const Py_UNICODE *s1, const Py_UNICODE *s2);
1335+
1336+
PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strchr(
1337+
const Py_UNICODE *s, Py_UNICODE c
1338+
);
1339+
1340+
13131341
#ifdef __cplusplus
13141342
}
13151343
#endif

Lib/test/test_frozen.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from test.test_support import TestFailed
1111
import sys, os
1212

13+
raise TestFailed, "test currently causes assertion in debug mode"
14+
1315
try:
1416
import __hello__
1517
except ImportError as x:

Lib/test/test_new.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def f(a): pass
143143
firstlineno, lnotab)
144144

145145
# new.code used to be a way to mutate a tuple...
146-
class S(str8):
146+
class S(str):
147147
pass
148148
t = (S("ab"),)
149149
d = new.code(argcount, kwonlyargcount, nlocals, stacksize,

Lib/test/test_sys.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,6 @@ def __hash__(self):
321321

322322
self.assertRaises(TypeError, sys.intern, S("abc"))
323323

324-
# It's still safe to pass these strings to routines that
325-
# call intern internally, e.g. PyObject_SetAttr().
326-
s = S("abc")
327-
setattr(s, s, s)
328-
self.assertEqual(getattr(s, s), s)
329-
330324
s = "never interned as unicode before"
331325
self.assert_(sys.intern(s) is s)
332326
s2 = s.swapcase().swapcase()
@@ -338,6 +332,12 @@ def __hash__(self):
338332

339333
self.assertRaises(TypeError, sys.intern, U("abc"))
340334

335+
# It's still safe to pass these strings to routines that
336+
# call intern internally, e.g. PyObject_SetAttr().
337+
s = U("abc")
338+
setattr(s, s, s)
339+
self.assertEqual(getattr(s, s), s)
340+
341341

342342
def test_main():
343343
test.test_support.run_unittest(SysModuleTest)

Modules/_codecsmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ escape_encode(PyObject *self,
172172
&PyString_Type, &str, &errors))
173173
return NULL;
174174

175-
size = PyUnicode_GET_SIZE(str);
175+
size = PyString_GET_SIZE(str);
176176
newsize = 4*size;
177177
if (newsize > PY_SSIZE_T_MAX || newsize / 4 != size) {
178178
PyErr_SetString(PyExc_OverflowError,

Modules/_hotshot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ get_fileno(ProfilerObject *self, PyCodeObject *fcode)
810810
PyObject *name = PyDict_GetItem(dict, obj);
811811
if (name == NULL) {
812812
if (pack_define_func(self, fileno, fcode->co_firstlineno,
813-
PyString_AS_STRING(fcode->co_name)) < 0) {
813+
PyUnicode_AsString(fcode->co_name)) < 0) {
814814
Py_DECREF(obj);
815815
return -1;
816816
}

Modules/cPickle.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,8 +1829,8 @@ save_global(Picklerobject *self, PyObject *args, PyObject *name)
18291829
(name_size = PyString_Size(global_name)) < 0)
18301830
goto finally;
18311831

1832-
module_str = PyString_AS_STRING((PyStringObject *)module);
1833-
name_str = PyString_AS_STRING((PyStringObject *)global_name);
1832+
module_str = PyUnicode_AsString(module);
1833+
name_str = PyUnicode_AsString(global_name);
18341834

18351835
/* XXX This can be doing a relative import. Clearly it shouldn't,
18361836
but I don't know how to stop it. :-( */
@@ -1842,7 +1842,7 @@ save_global(Picklerobject *self, PyObject *args, PyObject *name)
18421842
"OS", args, module);
18431843
goto finally;
18441844
}
1845-
klass = PyObject_GetAttrString(mod, name_str);
1845+
klass = PyObject_GetAttr(mod, global_name);
18461846
if (klass == NULL) {
18471847
cPickle_ErrFormat(PicklingError,
18481848
"Can't pickle %s: attribute lookup %s.%s "
@@ -2223,7 +2223,7 @@ save(Picklerobject *self, PyObject *args, int pers_save)
22232223
res = save_string(self, args, 0);
22242224
goto finally;
22252225
}
2226-
if ((type == &PyUnicode_Type) && (PyString_GET_SIZE(args) < 2)) {
2226+
if ((type == &PyUnicode_Type) && (PyUnicode_GET_SIZE(args) < 2)) {
22272227
res = save_unicode(self, args, 0);
22282228
goto finally;
22292229
}
@@ -3584,7 +3584,7 @@ load_global(Unpicklerobject *self)
35843584
Py_DECREF(module_name);
35853585
return bad_readline();
35863586
}
3587-
if ((class_name = PyString_FromStringAndSize(s, len - 1))) {
3587+
if ((class_name = PyUnicode_FromStringAndSize(s, len - 1))) {
35883588
class = find_class(module_name, class_name,
35893589
self->find_class);
35903590
Py_DECREF(class_name);
@@ -5379,7 +5379,7 @@ init_stuff(PyObject *module_dict)
53795379
{
53805380
PyObject *copy_reg, *t, *r;
53815381

5382-
#define INIT_STR(S) if (!( S ## _str=PyString_InternFromString(#S))) return -1;
5382+
#define INIT_STR(S) if (!( S ## _str=PyUnicode_InternFromString(#S))) return -1;
53835383

53845384
if (PyType_Ready(&Unpicklertype) < 0)
53855385
return -1;

0 commit comments

Comments
 (0)