mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-11 13:01:28 +02:00
49290: Replace stdio for buffered shell input.
The previous method allowed memory management to interact with signal handlers, causing occasional crashes on some system. Instead, use a simple pre-allocated buffer and raw system calls.
This commit is contained in:
parent
1a78e46564
commit
e5cd2dd980
3 changed files with 123 additions and 19 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
2021-08-27 Peter Stephenson <p.stephenson@samsung.com>
|
||||||
|
|
||||||
|
* 49290: Src/init.c, Src/input.c: Replace stdio for buffered
|
||||||
|
shell input to avoid memory management interacting with signal
|
||||||
|
handlers.
|
||||||
|
|
||||||
2021-08-27 Oliver Kiddle <opk@zsh.org>
|
2021-08-27 Oliver Kiddle <opk@zsh.org>
|
||||||
|
|
||||||
* Marlon: 49272: Completion/Base/Utility/_call_program:
|
* Marlon: 49272: Completion/Base/Utility/_call_program:
|
||||||
|
|
14
Src/init.c
14
Src/init.c
|
@ -1229,7 +1229,7 @@ setupshin(char *runscript)
|
||||||
/*
|
/*
|
||||||
* Finish setting up SHIN and its relatives.
|
* Finish setting up SHIN and its relatives.
|
||||||
*/
|
*/
|
||||||
bshin = SHIN ? fdopen(SHIN, "r") : stdin;
|
shinbufalloc();
|
||||||
if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
|
if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
|
||||||
#ifdef _IONBF
|
#ifdef _IONBF
|
||||||
setvbuf(stdin, NULL, _IONBF, 0);
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
@ -1384,9 +1384,9 @@ init_misc(char *cmd, char *zsh_name)
|
||||||
dosetopt(RESTRICTED, 1, 0, opts);
|
dosetopt(RESTRICTED, 1, 0, opts);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
if (SHIN >= 10)
|
if (SHIN >= 10)
|
||||||
fclose(bshin);
|
close(SHIN);
|
||||||
SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
|
SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
|
||||||
bshin = fdopen(SHIN, "r");
|
shinbufreset();
|
||||||
execstring(cmd, 0, 1, "cmdarg");
|
execstring(cmd, 0, 1, "cmdarg");
|
||||||
stopmsg = 1;
|
stopmsg = 1;
|
||||||
zexit((exit_pending || shell_exiting) ? exit_val : lastval, ZEXIT_NORMAL);
|
zexit((exit_pending || shell_exiting) ? exit_val : lastval, ZEXIT_NORMAL);
|
||||||
|
@ -1409,7 +1409,6 @@ source(char *s)
|
||||||
int tempfd = -1, fd, cj;
|
int tempfd = -1, fd, cj;
|
||||||
zlong oldlineno;
|
zlong oldlineno;
|
||||||
int oldshst, osubsh, oloops;
|
int oldshst, osubsh, oloops;
|
||||||
FILE *obshin;
|
|
||||||
char *old_scriptname = scriptname, *us;
|
char *old_scriptname = scriptname, *us;
|
||||||
char *old_scriptfilename = scriptfilename;
|
char *old_scriptfilename = scriptfilename;
|
||||||
unsigned char *ocs;
|
unsigned char *ocs;
|
||||||
|
@ -1426,7 +1425,6 @@ source(char *s)
|
||||||
|
|
||||||
/* save the current shell state */
|
/* save the current shell state */
|
||||||
fd = SHIN; /* store the shell input fd */
|
fd = SHIN; /* store the shell input fd */
|
||||||
obshin = bshin; /* store file handle for buffered shell input */
|
|
||||||
osubsh = subsh; /* store whether we are in a subshell */
|
osubsh = subsh; /* store whether we are in a subshell */
|
||||||
cj = thisjob; /* store our current job number */
|
cj = thisjob; /* store our current job number */
|
||||||
oldlineno = lineno; /* store our current lineno */
|
oldlineno = lineno; /* store our current lineno */
|
||||||
|
@ -1439,7 +1437,7 @@ source(char *s)
|
||||||
|
|
||||||
if (!prog) {
|
if (!prog) {
|
||||||
SHIN = tempfd;
|
SHIN = tempfd;
|
||||||
bshin = fdopen(SHIN, "r");
|
shinbufsave();
|
||||||
}
|
}
|
||||||
subsh = 0;
|
subsh = 0;
|
||||||
lineno = 1;
|
lineno = 1;
|
||||||
|
@ -1507,10 +1505,10 @@ source(char *s)
|
||||||
if (prog)
|
if (prog)
|
||||||
freeeprog(prog);
|
freeeprog(prog);
|
||||||
else {
|
else {
|
||||||
fclose(bshin);
|
close(SHIN);
|
||||||
fdtable[SHIN] = FDT_UNUSED;
|
fdtable[SHIN] = FDT_UNUSED;
|
||||||
SHIN = fd; /* the shell input fd */
|
SHIN = fd; /* the shell input fd */
|
||||||
bshin = obshin; /* file handle for buffered shell input */
|
shinbufrestore();
|
||||||
}
|
}
|
||||||
subsh = osubsh; /* whether we are in a subshell */
|
subsh = osubsh; /* whether we are in a subshell */
|
||||||
thisjob = cj; /* current job number */
|
thisjob = cj; /* current job number */
|
||||||
|
|
122
Src/input.c
122
Src/input.c
|
@ -80,11 +80,6 @@
|
||||||
/**/
|
/**/
|
||||||
int SHIN;
|
int SHIN;
|
||||||
|
|
||||||
/* buffered shell input for non-interactive shells */
|
|
||||||
|
|
||||||
/**/
|
|
||||||
FILE *bshin;
|
|
||||||
|
|
||||||
/* != 0 means we are reading input from a string */
|
/* != 0 means we are reading input from a string */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -129,7 +124,116 @@ static struct instacks *instack, *instacktop;
|
||||||
|
|
||||||
static int instacksz = INSTACK_INITIAL;
|
static int instacksz = INSTACK_INITIAL;
|
||||||
|
|
||||||
/* Read a line from bshin. Convert tokens and *
|
/* Size of buffer for non-interactive command input */
|
||||||
|
|
||||||
|
#define SHINBUFSIZE 8192
|
||||||
|
|
||||||
|
/* Input buffer for non-interactive command input */
|
||||||
|
static char *shinbuffer;
|
||||||
|
|
||||||
|
/* Pointer into shinbuffer */
|
||||||
|
static char *shinbufptr;
|
||||||
|
|
||||||
|
/* End of contents read into shinbuffer */
|
||||||
|
static char *shinbufendptr;
|
||||||
|
|
||||||
|
/* Entry on SHIN buffer save stack */
|
||||||
|
struct shinsaveentry {
|
||||||
|
/* Next entry on stack */
|
||||||
|
struct shinsaveentry *next;
|
||||||
|
/* Saved shinbuffer */
|
||||||
|
char *buffer;
|
||||||
|
/* Saved shinbufptr */
|
||||||
|
char *ptr;
|
||||||
|
/* Saved shinbufendptr */
|
||||||
|
char *endptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SHIN buffer save stack */
|
||||||
|
struct shinsaveentry *shinsavestack;
|
||||||
|
|
||||||
|
/* Reset the input buffer for SHIN, discarding any pending input */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
void
|
||||||
|
shinbufreset(void)
|
||||||
|
{
|
||||||
|
shinbufendptr = shinbufptr = shinbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a new shinbuffer
|
||||||
|
*
|
||||||
|
* Only called at shell initialisation and when saving on the stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**/
|
||||||
|
void
|
||||||
|
shinbufalloc(void)
|
||||||
|
{
|
||||||
|
shinbuffer = zalloc(SHINBUFSIZE);
|
||||||
|
shinbufreset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save entry on SHIN buffer save stack */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
void
|
||||||
|
shinbufsave(void)
|
||||||
|
{
|
||||||
|
struct shinsaveentry *entry =
|
||||||
|
(struct shinsaveentry *)zalloc(sizeof(struct shinsaveentry));
|
||||||
|
|
||||||
|
entry->next = shinsavestack;
|
||||||
|
entry->buffer = shinbuffer;
|
||||||
|
entry->ptr = shinbufptr;
|
||||||
|
entry->endptr = shinbufendptr;
|
||||||
|
|
||||||
|
shinsavestack = entry;
|
||||||
|
|
||||||
|
shinbufalloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore entry from SHIN buffer save stack */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
void
|
||||||
|
shinbufrestore(void)
|
||||||
|
{
|
||||||
|
struct shinsaveentry *entry = shinsavestack;
|
||||||
|
|
||||||
|
zfree(shinbuffer, SHINBUFSIZE);
|
||||||
|
|
||||||
|
shinbuffer = entry->buffer;
|
||||||
|
shinbufptr = entry->ptr;
|
||||||
|
shinbufendptr = entry->endptr;
|
||||||
|
|
||||||
|
shinsavestack = entry->next;
|
||||||
|
zfree(entry, sizeof(struct shinsaveentry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a character from SHIN, -1 if none available */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
shingetchar(void)
|
||||||
|
{
|
||||||
|
int nread;
|
||||||
|
|
||||||
|
if (shinbufptr < shinbufendptr)
|
||||||
|
return STOUC(*shinbufptr++);
|
||||||
|
|
||||||
|
shinbufreset();
|
||||||
|
do {
|
||||||
|
errno = 0;
|
||||||
|
nread = read(SHIN, shinbuffer, SHINBUFSIZE);
|
||||||
|
} while (nread < 0 && errno == EINTR);
|
||||||
|
if (nread <= 0)
|
||||||
|
return -1;
|
||||||
|
shinbufendptr = shinbuffer + nread;
|
||||||
|
return STOUC(*shinbufptr++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a line from SHIN. Convert tokens and *
|
||||||
* null characters to Meta c^32 character pairs. */
|
* null characters to Meta c^32 character pairs. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -147,11 +251,7 @@ shingetline(void)
|
||||||
winch_unblock();
|
winch_unblock();
|
||||||
dont_queue_signals();
|
dont_queue_signals();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Can't fgets() here because we need to accept '\0' bytes */
|
c = shingetchar();
|
||||||
do {
|
|
||||||
errno = 0;
|
|
||||||
c = fgetc(bshin);
|
|
||||||
} while (c < 0 && errno == EINTR);
|
|
||||||
if (c < 0 || c == '\n') {
|
if (c < 0 || c == '\n') {
|
||||||
winch_block();
|
winch_block();
|
||||||
restore_queue_signals(q);
|
restore_queue_signals(q);
|
||||||
|
|
Loading…
Reference in a new issue