Skip to content

Commit d374264

Browse files
committed
Refactor to use atomics & compare/exchange instead of holding a lock to avoid
possibility of deadlock upon re-entrance.
1 parent 40730d3 commit d374264

File tree

1 file changed

+18
-23
lines changed

1 file changed

+18
-23
lines changed

Modules/posixmodule.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15582,7 +15582,6 @@ typedef struct {
1558215582
ino_t d_ino;
1558315583
int dir_fd;
1558415584
#endif
15585-
_PyRecursiveMutex mutex;
1558615585
} DirEntry;
1558715586

1558815587
#define DirEntry_CAST(op) ((DirEntry *)(op))
@@ -15592,12 +15591,10 @@ DirEntry_dealloc(PyObject *op)
1559215591
{
1559315592
DirEntry *entry = DirEntry_CAST(op);
1559415593
PyTypeObject *tp = Py_TYPE(entry);
15595-
_PyRecursiveMutex_Lock(&entry->mutex);
1559615594
Py_XDECREF(entry->name);
1559715595
Py_XDECREF(entry->path);
1559815596
Py_XDECREF(entry->stat);
1559915597
Py_XDECREF(entry->lstat);
15600-
_PyRecursiveMutex_Unlock(&entry->mutex);
1560115598
freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
1560215599
free_func(entry);
1560315600
Py_DECREF(tp);
@@ -15715,16 +15712,19 @@ DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks)
1571515712
static PyObject *
1571615713
DirEntry_get_lstat(PyTypeObject *defining_class, DirEntry *self)
1571715714
{
15718-
/* Must be called with self->mutex held */
15719-
if (!self->lstat) {
15715+
if (!FT_ATOMIC_LOAD_PTR(self->lstat)) {
1572015716
PyObject *module = PyType_GetModule(defining_class);
15717+
PyObject *lstat;
15718+
PyObject *null_ptr = NULL;
1572115719
#ifdef MS_WINDOWS
15722-
self->lstat = _pystat_fromstructstat(module, &self->win32_lstat);
15720+
lstat = _pystat_fromstructstat(module, &self->win32_lstat);
1572315721
#else /* POSIX */
15724-
self->lstat = DirEntry_fetch_stat(module, self, 0);
15722+
lstat = DirEntry_fetch_stat(module, self, 0);
1572515723
#endif
15724+
if (!_Py_atomic_compare_exchange_ptr(&self->lstat, &null_ptr, lstat))
15725+
Py_XDECREF(lstat);
1572615726
}
15727-
return Py_XNewRef(self->lstat);
15727+
return Py_XNewRef(FT_ATOMIC_LOAD_PTR(self->lstat));
1572815728
}
1572915729

1573015730
/*[clinic input]
@@ -15742,31 +15742,28 @@ os_DirEntry_stat_impl(DirEntry *self, PyTypeObject *defining_class,
1574215742
int follow_symlinks)
1574315743
/*[clinic end generated code: output=23f803e19c3e780e input=e816273c4e67ee98]*/
1574415744
{
15745-
if (!follow_symlinks) {
15746-
_PyRecursiveMutex_Lock(&self->mutex);
15747-
PyObject *stat = DirEntry_get_lstat(defining_class, self);
15748-
_PyRecursiveMutex_Unlock(&self->mutex);
15749-
return stat;
15750-
}
15745+
if (!follow_symlinks)
15746+
return DirEntry_get_lstat(defining_class, self);
1575115747

15752-
_PyRecursiveMutex_Lock(&self->mutex);
15753-
if (!self->stat) {
15748+
if (!FT_ATOMIC_LOAD_PTR(self->stat)) {
15749+
PyObject *stat;
15750+
PyObject *null_ptr = NULL;
1575415751
int result = os_DirEntry_is_symlink_impl(self, defining_class);
1575515752
if (result == -1) {
15756-
_PyRecursiveMutex_Unlock(&self->mutex);
1575715753
return NULL;
1575815754
}
1575915755
if (result) {
1576015756
PyObject *module = PyType_GetModule(defining_class);
15761-
self->stat = DirEntry_fetch_stat(module, self, 1);
15757+
stat = DirEntry_fetch_stat(module, self, 1);
1576215758
}
1576315759
else {
15764-
self->stat = DirEntry_get_lstat(defining_class, self);
15760+
stat = DirEntry_get_lstat(defining_class, self);
1576515761
}
15762+
if (!_Py_atomic_compare_exchange_ptr(&self->stat, &null_ptr, stat))
15763+
Py_XDECREF(stat);
1576615764
}
15767-
_PyRecursiveMutex_Unlock(&self->mutex);
1576815765

15769-
return Py_XNewRef(self->stat);
15766+
return Py_XNewRef(FT_ATOMIC_LOAD_PTR(self->stat));
1577015767
}
1577115768

1577215769
/* Set exception and return -1 on error, 0 for False, 1 for True */
@@ -16039,7 +16036,6 @@ DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW)
1603916036
entry->stat = NULL;
1604016037
entry->lstat = NULL;
1604116038
entry->got_file_index = 0;
16042-
entry->mutex = (_PyRecursiveMutex){0};
1604316039

1604416040
entry->name = PyUnicode_FromWideChar(dataW->cFileName, -1);
1604516041
if (!entry->name)
@@ -16132,7 +16128,6 @@ DirEntry_from_posix_info(PyObject *module, path_t *path, const char *name,
1613216128
entry->path = NULL;
1613316129
entry->stat = NULL;
1613416130
entry->lstat = NULL;
16135-
entry->mutex = (_PyRecursiveMutex){0};
1613616131

1613716132
if (path->fd != -1) {
1613816133
entry->dir_fd = path->fd;

0 commit comments

Comments
 (0)