Skip to content

Commit eb6990c

Browse files
gh-155496: Use the bool return converter in the getpath module
hassuffix(), isfile() and isxfile() now use the bool return converter, as isabs() and isdir() already did. This also fixes a use after free in isxfile() on Windows: the path was freed before being passed to CompareStringOrdinal().
1 parent c7a7b19 commit eb6990c

2 files changed

Lines changed: 51 additions & 49 deletions

File tree

‎Modules/clinic/getpath.c.h‎

Lines changed: 22 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Modules/getpath.c‎

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ getpath_isabs_impl(PyObject *module, const wchar_t *path)
153153

154154

155155
/*[clinic input]
156-
getpath.hassuffix
156+
getpath.hassuffix -> bool
157157
158158
path as pathobj: unicode
159159
suffix as suffixobj: unicode
@@ -162,30 +162,24 @@ getpath.hassuffix
162162
Return True if the path ends with the suffix, ignoring the case.
163163
[clinic start generated code]*/
164164

165-
static PyObject *
165+
static int
166166
getpath_hassuffix_impl(PyObject *module, PyObject *pathobj,
167167
PyObject *suffixobj)
168-
/*[clinic end generated code: output=40e52a2ebe497e47 input=dffaf0ddc9d63647]*/
168+
/*[clinic end generated code: output=c4cbd6f2f567f83c input=4b477740575b94d8]*/
169169
{
170-
PyObject *r = NULL;
171-
const wchar_t *path;
172-
const wchar_t *suffix;
170+
int r = -1;
173171
Py_ssize_t len, suffixLen;
174-
path = PyUnicode_AsWideCharString(pathobj, &len);
172+
const wchar_t *path = PyUnicode_AsWideCharString(pathobj, &len);
175173
if (path) {
176-
suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen);
174+
const wchar_t *suffix = PyUnicode_AsWideCharString(suffixobj,
175+
&suffixLen);
177176
if (suffix) {
178-
if (suffixLen > len ||
177+
r = suffixLen <= len &&
179178
#ifdef MS_WINDOWS
180-
wcsicmp(&path[len - suffixLen], suffix) != 0
179+
wcsicmp(&path[len - suffixLen], suffix) == 0;
181180
#else
182-
wcscmp(&path[len - suffixLen], suffix) != 0
181+
wcscmp(&path[len - suffixLen], suffix) == 0;
183182
#endif
184-
) {
185-
r = Py_NewRef(Py_False);
186-
} else {
187-
r = Py_NewRef(Py_True);
188-
}
189183
PyMem_Free((void *)suffix);
190184
}
191185
PyMem_Free((void *)path);
@@ -219,81 +213,74 @@ getpath_isdir_impl(PyObject *module, const wchar_t *path)
219213

220214

221215
/*[clinic input]
222-
getpath.isfile
216+
getpath.isfile -> bool
223217
224218
path as pathobj: unicode
225219
/
226220
227221
Return True if the path is a regular file.
228222
[clinic start generated code]*/
229223

230-
static PyObject *
224+
static int
231225
getpath_isfile_impl(PyObject *module, PyObject *pathobj)
232-
/*[clinic end generated code: output=0060d782bd507740 input=71831c61d25e3f9e]*/
226+
/*[clinic end generated code: output=197acb7a5434b9d1 input=ba1c2746ec8f2f47]*/
233227
{
234-
235-
int isfile;
236228
#ifdef MS_WINDOWS
237229
wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
238230
if (path == NULL) {
239-
return NULL;
231+
return -1;
240232
}
241233

242234
DWORD attr = GetFileAttributesW(path);
243235
PyMem_Free(path);
244-
isfile = ((attr != INVALID_FILE_ATTRIBUTES)
245-
&& !(attr & FILE_ATTRIBUTE_DIRECTORY));
236+
return (attr != INVALID_FILE_ATTRIBUTES)
237+
&& !(attr & FILE_ATTRIBUTE_DIRECTORY);
246238
#else
247239
struct stat st;
248240
int res = _Py_stat(pathobj, &st);
249241
if (res == -2) {
250-
return NULL;
242+
return -1;
251243
}
252-
isfile = ((res == 0) && S_ISREG(st.st_mode));
244+
return (res == 0) && S_ISREG(st.st_mode);
253245
#endif
254-
return PyBool_FromLong(isfile);
255246
}
256247

257248

258249
/*[clinic input]
259-
getpath.isxfile
250+
getpath.isxfile -> bool
260251
261252
path as pathobj: unicode
262253
/
263254
264255
Return True if the path is an executable file.
265256
[clinic start generated code]*/
266257

267-
static PyObject *
258+
static int
268259
getpath_isxfile_impl(PyObject *module, PyObject *pathobj)
269-
/*[clinic end generated code: output=67348f84968ac985 input=4b272be4846d89a2]*/
260+
/*[clinic end generated code: output=2f0bc6708d945bc8 input=6d99faa90e262511]*/
270261
{
271-
272-
int isxfile;
273262
#ifdef MS_WINDOWS
274263
Py_ssize_t cchPath;
275264
wchar_t *path = PyUnicode_AsWideCharString(pathobj, &cchPath);
276265
if (path == NULL) {
277-
return NULL;
266+
return -1;
278267
}
279268

280269
DWORD attr = GetFileAttributesW(path);
270+
int isxfile = (attr != INVALID_FILE_ATTRIBUTES) &&
271+
!(attr & FILE_ATTRIBUTE_DIRECTORY) &&
272+
(cchPath >= 4) &&
273+
(CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL);
281274
PyMem_Free(path);
282-
isxfile = (attr != INVALID_FILE_ATTRIBUTES) &&
283-
!(attr & FILE_ATTRIBUTE_DIRECTORY) &&
284-
(cchPath >= 4) &&
285-
(CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL);
275+
return isxfile;
286276
#else
287277
struct stat st;
288278
int res = _Py_stat(pathobj, &st);
289279
if (res == -2) {
290-
return NULL;
280+
return -1;
291281
}
292-
isxfile = ((res == 0)
293-
&& S_ISREG(st.st_mode)
294-
&& (st.st_mode & 0111));
282+
return (res == 0) && S_ISREG(st.st_mode) && (st.st_mode & 0111);
295283
#endif
296-
return PyBool_FromLong(isxfile);
297284
}
298285

299286

0 commit comments

Comments
 (0)