@@ -16847,15 +16847,14 @@ ScandirIterator_is_closed(ScandirIterator *iterator)
1684716847static void
1684816848ScandirIterator_closedir(ScandirIterator *iterator)
1684916849{
16850+ // gh-152754: close under the critical section so it can't race iternext.
16851+ Py_BEGIN_CRITICAL_SECTION(iterator);
1685016852 HANDLE handle = iterator->handle;
16851-
16852- if (handle == INVALID_HANDLE_VALUE)
16853- return;
16854-
16855- iterator->handle = INVALID_HANDLE_VALUE;
16856- Py_BEGIN_ALLOW_THREADS
16857- FindClose(handle);
16858- Py_END_ALLOW_THREADS
16853+ if (handle != INVALID_HANDLE_VALUE) {
16854+ iterator->handle = INVALID_HANDLE_VALUE;
16855+ FindClose(handle);
16856+ }
16857+ Py_END_CRITICAL_SECTION();
1685916858}
1686016859
1686116860static PyObject *
@@ -16864,17 +16863,14 @@ ScandirIterator_iternext(PyObject *op)
1686416863 ScandirIterator *iterator = ScandirIterator_CAST(op);
1686516864 WIN32_FIND_DATAW *file_data = &iterator->file_data;
1686616865 BOOL success;
16867- PyObject *entry;
16866+ PyObject *entry = NULL ;
1686816867
16868+ // gh-152754: iterate under the critical section so close can't invalidate handle mid-use.
16869+ Py_BEGIN_CRITICAL_SECTION(iterator);
1686916870 /* Happens if the iterator is iterated twice, or closed explicitly */
16870- if (iterator->handle == INVALID_HANDLE_VALUE)
16871- return NULL;
16872-
16873- while (1) {
16871+ while (iterator->handle != INVALID_HANDLE_VALUE) {
1687416872 if (!iterator->first_time) {
16875- Py_BEGIN_ALLOW_THREADS
1687616873 success = FindNextFileW(iterator->handle, file_data);
16877- Py_END_ALLOW_THREADS
1687816874 if (!success) {
1687916875 /* Error or no more files */
1688016876 if (GetLastError() != ERROR_NO_MORE_FILES)
@@ -16890,14 +16886,17 @@ ScandirIterator_iternext(PyObject *op)
1689016886 {
1689116887 PyObject *module = PyType_GetModule(Py_TYPE(iterator));
1689216888 entry = DirEntry_from_find_data(module, &iterator->path, file_data);
16893- if (!entry)
16894- break;
16895- return entry;
16889+ break;
1689616890 }
1689716891
1689816892 /* Loop till we get a non-dot directory or finish iterating */
1689916893 }
1690016894
16895+ Py_END_CRITICAL_SECTION();
16896+
16897+ if (entry != NULL)
16898+ return entry;
16899+
1690116900 /* Error or no more files */
1690216901 ScandirIterator_closedir(iterator);
1690316902 return NULL;
@@ -16914,21 +16913,19 @@ ScandirIterator_is_closed(ScandirIterator *iterator)
1691416913static void
1691516914ScandirIterator_closedir(ScandirIterator *iterator)
1691616915{
16916+ // gh-152754: close under the critical section so it can't race iternext.
16917+ Py_BEGIN_CRITICAL_SECTION(iterator);
1691716918 DIR *dirp = iterator->dirp;
16918-
16919- if (!dirp)
16920- return;
16921-
16922- iterator->dirp = NULL;
16923- Py_BEGIN_ALLOW_THREADS
16919+ if (dirp != NULL) {
16920+ iterator->dirp = NULL;
1692416921#ifdef HAVE_FDOPENDIR
16925- if (iterator->path.is_fd) {
16926- rewinddir(dirp);
16927- }
16922+ if (iterator->path.is_fd) {
16923+ rewinddir(dirp);
16924+ }
1692816925#endif
16929- closedir(dirp);
16930- Py_END_ALLOW_THREADS
16931- return ;
16926+ closedir(dirp);
16927+ }
16928+ Py_END_CRITICAL_SECTION() ;
1693216929}
1693316930
1693416931static PyObject *
@@ -16938,17 +16935,14 @@ ScandirIterator_iternext(PyObject *op)
1693816935 struct dirent *direntp;
1693916936 Py_ssize_t name_len;
1694016937 int is_dot;
16941- PyObject *entry;
16938+ PyObject *entry = NULL ;
1694216939
16940+ // gh-152754: iterate under the critical section so close can't free dirp mid-use.
16941+ Py_BEGIN_CRITICAL_SECTION(iterator);
1694316942 /* Happens if the iterator is iterated twice, or closed explicitly */
16944- if (!iterator->dirp)
16945- return NULL;
16946-
16947- while (1) {
16943+ while (iterator->dirp != NULL) {
1694816944 errno = 0;
16949- Py_BEGIN_ALLOW_THREADS
1695016945 direntp = readdir(iterator->dirp);
16951- Py_END_ALLOW_THREADS
1695216946
1695316947 if (!direntp) {
1695416948 /* Error or no more files */
@@ -16970,13 +16964,15 @@ ScandirIterator_iternext(PyObject *op)
1697016964 , direntp->d_type
1697116965#endif
1697216966 );
16973- if (!entry)
16974- break;
16975- return entry;
16967+ break;
1697616968 }
1697716969
1697816970 /* Loop till we get a non-dot directory or finish iterating */
1697916971 }
16972+ Py_END_CRITICAL_SECTION();
16973+
16974+ if (entry != NULL)
16975+ return entry;
1698016976
1698116977 /* Error or no more files */
1698216978 ScandirIterator_closedir(iterator);
0 commit comments