Skip to content

Commit 0f692ce

Browse files
ZeroIntensitykumaraditya303
authored andcommitted
fix race
1 parent 7303f06 commit 0f692ce

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

Lib/test/test_capi/test_unicode.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import unittest
22
import sys
33
from test import support
4-
from test.support import import_helper
4+
from test.support import threading_helper
55

66
try:
77
import _testcapi
@@ -1005,6 +1005,23 @@ def test_asutf8(self):
10051005
self.assertRaises(TypeError, unicode_asutf8, [], 0)
10061006
# CRASHES unicode_asutf8(NULL, 0)
10071007

1008+
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
1009+
@threading_helper.requires_working_threading()
1010+
def test_asutf8_race(self):
1011+
from _testcapi import unicode_asutf8
1012+
from threading import Thread
1013+
1014+
data = "😊"
1015+
1016+
def worker():
1017+
for _ in range(1000):
1018+
self.assertEqual(unicode_asutf8(data, 5), b'\xf0\x9f\x98\x8a\0')
1019+
1020+
threads = [Thread(target=worker) for _ in range(10)]
1021+
with threading_helper.start_threads(threads):
1022+
pass
1023+
1024+
10081025
@support.cpython_only
10091026
@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
10101027
def test_asutf8andsize(self):

Objects/unicodeobject.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,14 @@ NOTE: In the interpreter's initialization phase, some globals are currently
118118
(assert(_PyUnicode_CHECK(op)), \
119119
PyUnicode_IS_COMPACT_ASCII(op) ? \
120120
((char*)(_PyASCIIObject_CAST(op) + 1)) : \
121-
_PyUnicode_UTF8(op))
121+
FT_ATOMIC_LOAD_PTR(_PyUnicode_UTF8(op)))
122122
#define _PyUnicode_UTF8_LENGTH(op) \
123123
(_PyCompactUnicodeObject_CAST(op)->utf8_length)
124124
#define PyUnicode_UTF8_LENGTH(op) \
125125
(assert(_PyUnicode_CHECK(op)), \
126126
PyUnicode_IS_COMPACT_ASCII(op) ? \
127127
_PyASCIIObject_CAST(op)->length : \
128-
_PyUnicode_UTF8_LENGTH(op))
128+
FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_UTF8_LENGTH(op)))
129129

130130
#define _PyUnicode_LENGTH(op) \
131131
(_PyASCIIObject_CAST(op)->length)
@@ -667,16 +667,16 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
667667
CHECK(ascii->state.compact == 0);
668668
CHECK(data != NULL);
669669
if (ascii->state.ascii) {
670-
CHECK(compact->utf8 == data);
671-
CHECK(compact->utf8_length == ascii->length);
670+
CHECK(FT_ATOMIC_LOAD_PTR(compact->utf8) == data);
671+
CHECK(FT_ATOMIC_LOAD_SSIZE_RELAXED(compact->utf8_length) == ascii->length);
672672
}
673673
else {
674-
CHECK(compact->utf8 != data);
674+
CHECK(FT_ATOMIC_LOAD_PTR(compact->utf8) != data);
675675
}
676676
}
677677

678-
if (compact->utf8 == NULL)
679-
CHECK(compact->utf8_length == 0);
678+
if (FT_ATOMIC_LOAD_PTR(compact->utf8) == NULL)
679+
CHECK(FT_ATOMIC_LOAD_SSIZE_RELAXED(compact->utf8_length) == 0);
680680
}
681681

682682
/* check that the best kind is used: O(n) operation */
@@ -5823,7 +5823,11 @@ unicode_fill_utf8(PyObject *unicode)
58235823
{
58245824
/* the string cannot be ASCII, or PyUnicode_UTF8() would be set */
58255825
assert(!PyUnicode_IS_ASCII(unicode));
5826-
5826+
int ret = 0;
5827+
Py_BEGIN_CRITICAL_SECTION(unicode);
5828+
if (FT_ATOMIC_LOAD_PTR(_PyUnicode_UTF8(unicode))) {
5829+
goto exit;
5830+
}
58275831
int kind = PyUnicode_KIND(unicode);
58285832
const void *data = PyUnicode_DATA(unicode);
58295833
Py_ssize_t size = PyUnicode_GET_LENGTH(unicode);
@@ -5849,7 +5853,8 @@ unicode_fill_utf8(PyObject *unicode)
58495853
}
58505854
if (end == NULL) {
58515855
_PyBytesWriter_Dealloc(&writer);
5852-
return -1;
5856+
ret = -1;
5857+
goto exit;
58535858
}
58545859

58555860
const char *start = writer.use_small_buffer ? writer.small_buffer :
@@ -5860,14 +5865,17 @@ unicode_fill_utf8(PyObject *unicode)
58605865
if (cache == NULL) {
58615866
_PyBytesWriter_Dealloc(&writer);
58625867
PyErr_NoMemory();
5863-
return -1;
5868+
ret = -1;
5869+
goto exit;
58645870
}
5865-
_PyUnicode_UTF8(unicode) = cache;
5866-
_PyUnicode_UTF8_LENGTH(unicode) = len;
58675871
memcpy(cache, start, len);
58685872
cache[len] = '\0';
5873+
FT_ATOMIC_STORE_SSIZE_RELAXED(_PyUnicode_UTF8_LENGTH(unicode), len);
5874+
FT_ATOMIC_STORE_PTR(_PyUnicode_UTF8(unicode), cache);
58695875
_PyBytesWriter_Dealloc(&writer);
5870-
return 0;
5876+
exit:;
5877+
Py_END_CRITICAL_SECTION();
5878+
return ret;
58715879
}
58725880

58735881
PyObject *

0 commit comments

Comments
 (0)