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.
This commit is contained in:
Benjamin Peterson 2020-07-28 17:57:12 -07:00 committed by GitHub
parent f6a16e8a82
commit a74eea238f
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 #endif
n = 100;
p = (char *)PyMem_RawMalloc(n);
if (p == NULL) {
PyEval_RestoreThread(tstate);
PyErr_NoMemory();
PyEval_SaveThread();
return NULL;
}
fflush(sys_stdout); fflush(sys_stdout);
if (prompt) { if (prompt) {
fprintf(stderr, "%s", prompt); fprintf(stderr, "%s", prompt);
} }
fflush(stderr); fflush(stderr);
switch (my_fgets(tstate, p, (int)n, sys_stdin)) { n = 0;
case 0: /* Normal case */ p = NULL;
break; do {
case 1: /* Interrupt */ size_t incr = (n > 0) ? n + 2 : 100;
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;
if (incr > INT_MAX) { if (incr > INT_MAX) {
PyMem_RawFree(p); PyMem_RawFree(p);
PyEval_RestoreThread(tstate); PyEval_RestoreThread(tstate);
@ -329,7 +308,6 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
PyEval_SaveThread(); PyEval_SaveThread();
return NULL; return NULL;
} }
pr = (char *)PyMem_RawRealloc(p, n + incr); pr = (char *)PyMem_RawRealloc(p, n + incr);
if (pr == NULL) { if (pr == NULL) {
PyMem_RawFree(p); PyMem_RawFree(p);
@ -339,12 +317,18 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
return NULL; return NULL;
} }
p = pr; p = pr;
int err = my_fgets(tstate, p + n, incr, sys_stdin);
if (my_fgets(tstate, p+n, (int)incr, sys_stdin) != 0) { if (err == 1) {
// Interrupt
PyMem_RawFree(p);
return NULL;
} else if (err != 0) {
// EOF or error
p[n] = '\0';
break; break;
} }
n += strlen(p+n); n += strlen(p + n);
} } while (p[n-1] != '\n');
pr = (char *)PyMem_RawRealloc(p, n+1); pr = (char *)PyMem_RawRealloc(p, n+1);
if (pr == NULL) { if (pr == NULL) {