Skip to content

Commit 9fb6bfb

Browse files
[3.13] gh-122581: Avoid data races when collecting parser statistics (GH-122694) (#122733)
gh-122581: Avoid data races when collecting parser statistics (GH-122694) (cherry picked from commit ce0d66c) Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
1 parent 5c161cb commit 9fb6bfb

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

Include/internal/pycore_parser.h

+19
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ extern "C" {
2121
struct _parser_runtime_state {
2222
#ifdef Py_DEBUG
2323
long memo_statistics[_PYPEGEN_NSTATISTICS];
24+
#ifdef Py_GIL_DISABLED
25+
PyMutex mutex;
26+
#endif
2427
#else
2528
int _not_used;
2629
#endif
2730
struct _expr dummy_name;
2831
};
2932

3033
_Py_DECLARE_STR(empty, "")
34+
#if defined(Py_DEBUG) && defined(Py_GIL_DISABLED)
3135
#define _parser_runtime_state_INIT \
3236
{ \
37+
.mutex = {0}, \
3338
.dummy_name = { \
3439
.kind = Name_kind, \
3540
.v.Name.id = &_Py_STR(empty), \
@@ -40,6 +45,20 @@ _Py_DECLARE_STR(empty, "")
4045
.end_col_offset = 0, \
4146
}, \
4247
}
48+
#else
49+
#define _parser_runtime_state_INIT \
50+
{ \
51+
.dummy_name = { \
52+
.kind = Name_kind, \
53+
.v.Name.id = &_Py_STR(empty), \
54+
.v.Name.ctx = Load, \
55+
.lineno = 1, \
56+
.col_offset = 0, \
57+
.end_lineno = 1, \
58+
.end_col_offset = 0, \
59+
}, \
60+
}
61+
#endif
4362

4463
extern struct _mod* _PyParser_ASTFromString(
4564
const char *str,

Parser/pegen.c

+17
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,22 @@ _PyPegen_fill_token(Parser *p)
296296
#define NSTATISTICS _PYPEGEN_NSTATISTICS
297297
#define memo_statistics _PyRuntime.parser.memo_statistics
298298

299+
#ifdef Py_GIL_DISABLED
300+
#define MUTEX_LOCK() PyMutex_Lock(&_PyRuntime.parser.mutex)
301+
#define MUTEX_UNLOCK() PyMutex_Unlock(&_PyRuntime.parser.mutex)
302+
#else
303+
#define MUTEX_LOCK()
304+
#define MUTEX_UNLOCK()
305+
#endif
306+
299307
void
300308
_PyPegen_clear_memo_statistics(void)
301309
{
310+
MUTEX_LOCK();
302311
for (int i = 0; i < NSTATISTICS; i++) {
303312
memo_statistics[i] = 0;
304313
}
314+
MUTEX_UNLOCK();
305315
}
306316

307317
PyObject *
@@ -311,18 +321,23 @@ _PyPegen_get_memo_statistics(void)
311321
if (ret == NULL) {
312322
return NULL;
313323
}
324+
325+
MUTEX_LOCK();
314326
for (int i = 0; i < NSTATISTICS; i++) {
315327
PyObject *value = PyLong_FromLong(memo_statistics[i]);
316328
if (value == NULL) {
329+
MUTEX_UNLOCK();
317330
Py_DECREF(ret);
318331
return NULL;
319332
}
320333
// PyList_SetItem borrows a reference to value.
321334
if (PyList_SetItem(ret, i, value) < 0) {
335+
MUTEX_UNLOCK();
322336
Py_DECREF(ret);
323337
return NULL;
324338
}
325339
}
340+
MUTEX_UNLOCK();
326341
return ret;
327342
}
328343
#endif
@@ -348,7 +363,9 @@ _PyPegen_is_memoized(Parser *p, int type, void *pres)
348363
if (count <= 0) {
349364
count = 1;
350365
}
366+
MUTEX_LOCK();
351367
memo_statistics[type] += count;
368+
MUTEX_UNLOCK();
352369
}
353370
#endif
354371
p->mark = m->mark;

0 commit comments

Comments
 (0)