Skip to content

Commit a74eea2

Browse files
authored
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.
1 parent f6a16e8 commit a74eea2

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
@@ -291,45 +291,23 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
291291
}
292292
#endif
293293

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

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

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

0 commit comments

Comments
 (0)