View Issue Details

IDProjectCategoryView StatusLast Update
0000534tcshGeneralpublic2024-06-11 13:48
ReporterMProG10 Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Summary0000534: Fix variable expansion on expressions.
DescriptionIt's known variables expand earlier than expression evaluations. The procedure
if ( $?a && "$a" != ) echo "$a"

would fail if a isn't set. The correct behavior is to evaluate $?a first, and, if expanded to zero, cancel further processing.

This work remedies the issue by postponing variable expansions during expression evaluations. The function Dfix1 is used for I/O redirections, and fails if the expansion is, if not quoted, null or larger than one word/vector. I believe this behavior is fine.

This work was also supposed to fix $< expansions on pipes and redirections. I had some success with a fix, but ends up blocking the shell, making it unusable and uninterruptible.
Additional Informationhttps://github.com/tcsh-org/tcsh/pull/107
TagsNo tags attached.

Activities

MProG10

2024-06-11 13:48

reporter  

sh.dol.c.diff (331 bytes)   
--- a/sh.dol.c
+++ b/sh.dol.c
@@ -54,8 +54,6 @@ static Char *Dcp, *const *Dvp;	/* Input vector for Dreadc */
 
 #define	unDgetC(c)	Dpeekc = c
 
-#define QUOTES		(_QF|_QB|_ESC)	/* \ ' " ` */
-
 /*
  * The following variables give the information about the current
  * $ expansion, recording the current word position, the remaining
sh.dol.c.diff (331 bytes)   
sh.exp.c.diff (538 bytes)   
--- a/sh.exp.c
+++ b/sh.exp.c
@@ -579,6 +579,19 @@ exp6(Char ***vp, int ignore)
 	etraci("exp6 {} status", getstatus(), vp);
 	return putn(getstatus() == 0);
     }
+    for (cp = **vp; *cp; cp++)
+	if (cmap(*cp, _DOL | QUOTES)) {
+	    Char *buf;
+
+	    if (ignore & TEXP_IGNORE) {
+		(*vp)++;
+		return Strsave(STRNULL);
+	    }
+	    cleanup_push(cp = Dfix1(*(*vp)++), xfree);
+	    buf = globone(cp, G_ERROR);
+	    cleanup_until(cp);
+	    return buf;
+	}
     if (isa(**vp, ANYOP))
 	return (Strsave(STRNULL));
     cp = *(*vp)++;
sh.exp.c.diff (538 bytes)   
sh.h.diff (275 bytes)   
--- a/sh.h
+++ b/sh.h
@@ -1305,5 +1305,6 @@ extern int    filec;
 #define TEXP_IGNORE 1	/* in ignore, it means to ignore value, just parse */
 #define TEXP_NOGLOB 2	/* in ignore, it means not to globone */
 
+#define QUOTES (_QB|_QF|_ESC) /* \ " ' ` */
 
 #endif /* _h_sh */
sh.h.diff (275 bytes)   
sh.sem.c.diff (1,215 bytes)   
--- a/sh.sem.c
+++ b/sh.sem.c
@@ -83,7 +83,7 @@ void
 execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
     int do_glob)
 {
-    int    forked = 0;
+    int    expr, forked = 0;
     const struct biltins * volatile bifunc;
     pid_t pid = 0;
     int     pv[2];
@@ -188,7 +188,11 @@ execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
 	    memmove(t->t_dcom[0], t->t_dcom[0] + 1,
 		    (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0]));
-	if ((t->t_dflg & F_REPEAT) == 0)
+	if (!(expr = ((bifunc = isbfunc(t)) &&
+		      (bifunc->bfunct == doexit ||
+		       bifunc->bfunct == dolet ||
+		       bifunc->bfunct == doif ||
+		       bifunc->bfunct == dowhile))))
 	    Dfix(t);		/* $ " ' \ */
 	if (t->t_dcom[0] == 0) {
 	    return;
@@ -290,10 +294,6 @@ execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 
 	/* is it a command */
 	if (t->t_dtyp == NODE_COMMAND) {
-	    /*
-	     * Check if we have a builtin function and remember which one.
-	     */
-	    bifunc = isbfunc(t);
  	    if (noexec) {
 		/*
 		 * Continue for builtins that are part of the scripting language
sh.sem.c.diff (1,215 bytes)   

Issue History

Date Modified Username Field Change
2024-06-11 13:48 MProG10 New Issue
2024-06-11 13:48 MProG10 File Added: sh.dol.c.diff
2024-06-11 13:48 MProG10 File Added: sh.exp.c.diff
2024-06-11 13:48 MProG10 File Added: sh.h.diff
2024-06-11 13:48 MProG10 File Added: sh.sem.c.diff