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:
parent
f6a16e8a82
commit
a74eea238f
|
@ -0,0 +1 @@
|
||||||
|
Handle interrupts that come after EOF correctly in ``PyOS_StdioReadline``.
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue