Skip to content

Commit 7cfede6

Browse files
closes bpo-38156: Always handle interrupts in PyOS_StdioReadline. (GH-21569)
This consolidates the handling of my_fgets return values, so that interrupts are always handled, even if they come after EOF. I believe PyOS_StdioReadline is still buggy in that I/O errors will not result in a proper Python exception being set. However, that is a separate issue. (cherry picked from commit a74eea2) Co-authored-by: Benjamin Peterson <[email protected]>
1 parent 5e0ce46 commit 7cfede6

File tree

2 files changed

+15
-30
lines changed

2 files changed

+15
-30
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Handle interrupts that come after EOF correctly in ``PyOS_StdioReadline``.

Parser/myreadline.c

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -292,45 +292,23 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
292292
}
293293
#endif
294294

295-
n = 100;
296-
p = (char *)PyMem_RawMalloc(n);
297-
if (p == NULL) {
298-
PyEval_RestoreThread(tstate);
299-
PyErr_NoMemory();
300-
PyEval_SaveThread();
301-
return NULL;
302-
}
303-
304295
fflush(sys_stdout);
305296
if (prompt) {
306297
fprintf(stderr, "%s", prompt);
307298
}
308299
fflush(stderr);
309300

310-
switch (my_fgets(tstate, p, (int)n, sys_stdin)) {
311-
case 0: /* Normal case */
312-
break;
313-
case 1: /* Interrupt */
314-
PyMem_RawFree(p);
315-
return NULL;
316-
case -1: /* EOF */
317-
case -2: /* Error */
318-
default: /* Shouldn't happen */
319-
*p = '\0';
320-
break;
321-
}
322-
323-
n = strlen(p);
324-
while (n > 0 && p[n-1] != '\n') {
325-
size_t incr = n+2;
301+
n = 0;
302+
p = NULL;
303+
do {
304+
size_t incr = (n > 0) ? n + 2 : 100;
326305
if (incr > INT_MAX) {
327306
PyMem_RawFree(p);
328307
PyEval_RestoreThread(tstate);
329308
PyErr_SetString(PyExc_OverflowError, "input line too long");
330309
PyEval_SaveThread();
331310
return NULL;
332311
}
333-
334312
pr = (char *)PyMem_RawRealloc(p, n + incr);
335313
if (pr == NULL) {
336314
PyMem_RawFree(p);
@@ -340,12 +318,18 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
340318
return NULL;
341319
}
342320
p = pr;
343-
344-
if (my_fgets(tstate, p+n, (int)incr, sys_stdin) != 0) {
321+
int err = my_fgets(tstate, p + n, incr, sys_stdin);
322+
if (err == 1) {
323+
// Interrupt
324+
PyMem_RawFree(p);
325+
return NULL;
326+
} else if (err != 0) {
327+
// EOF or error
328+
p[n] = '\0';
345329
break;
346330
}
347-
n += strlen(p+n);
348-
}
331+
n += strlen(p + n);
332+
} while (p[n-1] != '\n');
349333

350334
pr = (char *)PyMem_RawRealloc(p, n+1);
351335
if (pr == NULL) {

0 commit comments

Comments
 (0)