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 a74eea238f)

Co-authored-by: Benjamin Peterson <benjamin@python.org>
This commit is contained in:
Miss Islington (bot) 2020-07-28 18:16:19 -07:00 committed by GitHub
parent aa16ac7433
commit 22216107f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 30 deletions

View File

@ -0,0 +1 @@
Handle interrupts that come after EOF correctly in ``PyOS_StdioReadline``.

View File

@ -291,37 +291,16 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
}
#endif
n = 100;
p = (char *)PyMem_RawMalloc(n);
if (p == NULL) {
PyEval_RestoreThread(tstate);
PyErr_NoMemory();
PyEval_SaveThread();
return NULL;
}
fflush(sys_stdout);
if (prompt) {
fprintf(stderr, "%s", prompt);
}
fflush(stderr);
switch (my_fgets(tstate, p, (int)n, sys_stdin)) {
case 0: /* Normal case */
break;
case 1: /* Interrupt */
PyMem_RawFree(p);
return NULL;
case -1: /* EOF */
case -2: /* Error */
default: /* Shouldn't happen */
*p = '\0';
break;
}
n = strlen(p);
while (n > 0 && p[n-1] != '\n') {
size_t incr = n+2;
n = 0;
p = NULL;
do {
size_t incr = (n > 0) ? n + 2 : 100;
if (incr > INT_MAX) {
PyMem_RawFree(p);
PyEval_RestoreThread(tstate);
@ -329,7 +308,6 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
PyEval_SaveThread();
return NULL;
}
pr = (char *)PyMem_RawRealloc(p, n + incr);
if (pr == NULL) {
PyMem_RawFree(p);
@ -339,12 +317,18 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
return NULL;
}
p = pr;
if (my_fgets(tstate, p+n, (int)incr, sys_stdin) != 0) {
int err = my_fgets(tstate, p + n, incr, sys_stdin);
if (err == 1) {
// Interrupt
PyMem_RawFree(p);
return NULL;
} else if (err != 0) {
// EOF or error
p[n] = '\0';
break;
}
n += strlen(p+n);
}
n += strlen(p + n);
} while (p[n-1] != '\n');
pr = (char *)PyMem_RawRealloc(p, n+1);
if (pr == NULL) {