1
0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-11-15 13:34:18 +01: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:
Peter Stephenson 2021-08-27 09:36:06 +01:00
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>
* Marlon: 49272: Completion/Base/Utility/_call_program:

@ -1229,7 +1229,7 @@ setupshin(char *runscript)
/*
* Finish setting up SHIN and its relatives.
*/
bshin = SHIN ? fdopen(SHIN, "r") : stdin;
shinbufalloc();
if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
#ifdef _IONBF
setvbuf(stdin, NULL, _IONBF, 0);
@ -1384,9 +1384,9 @@ init_misc(char *cmd, char *zsh_name)
dosetopt(RESTRICTED, 1, 0, opts);
if (cmd) {
if (SHIN >= 10)
fclose(bshin);
close(SHIN);
SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
bshin = fdopen(SHIN, "r");
shinbufreset();
execstring(cmd, 0, 1, "cmdarg");
stopmsg = 1;
zexit((exit_pending || shell_exiting) ? exit_val : lastval, ZEXIT_NORMAL);
@ -1409,7 +1409,6 @@ source(char *s)
int tempfd = -1, fd, cj;
zlong oldlineno;
int oldshst, osubsh, oloops;
FILE *obshin;
char *old_scriptname = scriptname, *us;
char *old_scriptfilename = scriptfilename;
unsigned char *ocs;
@ -1426,7 +1425,6 @@ source(char *s)
/* save the current shell state */
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 */
cj = thisjob; /* store our current job number */
oldlineno = lineno; /* store our current lineno */
@ -1439,7 +1437,7 @@ source(char *s)
if (!prog) {
SHIN = tempfd;
bshin = fdopen(SHIN, "r");
shinbufsave();
}
subsh = 0;
lineno = 1;
@ -1507,10 +1505,10 @@ source(char *s)
if (prog)
freeeprog(prog);
else {
fclose(bshin);
close(SHIN);
fdtable[SHIN] = FDT_UNUSED;
SHIN = fd; /* the shell input fd */
bshin = obshin; /* file handle for buffered shell input */
shinbufrestore();
}
subsh = osubsh; /* whether we are in a subshell */
thisjob = cj; /* current job number */

@ -80,11 +80,6 @@
/**/
int SHIN;
/* buffered shell input for non-interactive shells */
/**/
FILE *bshin;
/* != 0 means we are reading input from a string */
/**/
@ -129,7 +124,116 @@ static struct instacks *instack, *instacktop;
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. */
/**/
@ -147,11 +251,7 @@ shingetline(void)
winch_unblock();
dont_queue_signals();
for (;;) {
/* Can't fgets() here because we need to accept '\0' bytes */
do {
errno = 0;
c = fgetc(bshin);
} while (c < 0 && errno == EINTR);
c = shingetchar();
if (c < 0 || c == '\n') {
winch_block();
restore_queue_signals(q);