diff mbox

unset/null variables should expand to 0 during arithmetic expansion

Message ID A7A04C3C-65D2-404B-B65F-0053A4D2E78C@pomona.edu (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show

Commit Message

Michael Greenberg Jan. 19, 2017, 9:06 p.m. UTC
Hi,

It seems like dash has a subtly incorrect arithmetic expansion for variables that are unset. For example, consider the following program:

unset x ; echo $((x+=2))

Running bash on this program echoes the number 2 to standard out and sets x to 2. Running dash (git HEAD/release 0.5.9.1) yields an error:

src/dash: 1: Illegal number: 

Now, bash and dash disagreeing isn’t such a big deal. But it seems like the standard indicates bash’s defaulting is correct for unset variables. According to <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04>, “the arithmetic expression shall be processed according to the rules given in Arithmetic Precision and Operations”, which says “all variables shall be initialized to zero if they are not otherwise assigned by the input to the application” <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_01_02_01>.

The standard is a little bit unclear about what to do for variables that are set to null (or non-numeric values). I’d interpret the standard as defaulting for unset variables, having null and other non-numeric strings cause some kind of error. bash, as usual, goes well beyond what the standard indicates: any non-numerical value is defaulted to 0. So:

x="" ; echo $((x+=2))

x=“yo” ; echo $((x+=2))

both yield 2! If you ask me, that’s a bridge too far—and asking for bugs.

I should add that my student (Austin Blatt, CC-ed) noticed this issue; I wrote the attached, single-line fix.

Cheers,
Michael

Signed-off-by: Michael Greenberg <michael.greenberg@pomona.edu>

Comments

Martijn Dekker Jan. 30, 2017, 12:13 a.m. UTC | #1
Op 19-01-17 om 21:06 schreef Michael Greenberg:
> unset x ; echo $((x+=2))
> 
> Running bash on this program echoes the number 2 to standard out and sets x to 2. Running dash (git HEAD/release 0.5.9.1) yields an error:
> 
> src/dash: 1: Illegal number: 

Yes, looks like a dash-specific bug. The related shells Busybox ash and
FreeBSD /bin/sh act like POSIX says they should.

> The standard is a little bit unclear about what to do for variables that are set to null (or non-numeric values). I’d interpret the standard as defaulting for unset variables, having null and other non-numeric strings cause some kind of error. bash, as usual, goes well beyond what the standard indicates: any non-numerical value is defaulted to 0. So:
> 
> x="" ; echo $((x+=2))
> 
> x=“yo” ; echo $((x+=2))
> 
> both yield 2! If you ask me, that’s a bridge too far—and asking for bugs.

That's recursive arithmetic expression parsing in bash, ksh and zsh; if
the value of a variable is an arithmetic expression (including simply
another variable name, such as "yo") this is evaluated, which in this
case means the value of "x" is taken as the value of "yo" which is taken
as zero. That behaviour is not specified by POSIX, of course.

- M.

--
To unsubscribe from this list: send the line "unsubscribe dash" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michael Greenberg Feb. 1, 2017, 6:28 p.m. UTC | #2
Hi Martijn,

> On Jan 29, 2017, at 4:13 PM, Martijn Dekker <martijn@inlv.org> wrote:

> 

> Op 19-01-17 om 21:06 schreef Michael Greenberg:

>> unset x ; echo $((x+=2))

>> 

>> Running bash on this program echoes the number 2 to standard out and sets x to 2. Running dash (git HEAD/release 0.5.9.1) yields an error:

>> 

>> src/dash: 1: Illegal number: 

> 

> Yes, looks like a dash-specific bug. The related shells Busybox ash and

> FreeBSD /bin/sh act like POSIX says they should.


Great! Please pardon my naivete, but is there anything else I can or should do to see that this bug patch gets accepted and applied?

>> The standard is a little bit unclear about what to do for variables that are set to null (or non-numeric values). I’d interpret the standard as defaulting for unset variables, having null and other non-numeric strings cause some kind of error. bash, as usual, goes well beyond what the standard indicates: any non-numerical value is defaulted to 0. So:

>> 

>> x="" ; echo $((x+=2))

>> 

>> x=“yo” ; echo $((x+=2))

>> 

>> both yield 2! If you ask me, that’s a bridge too far—and asking for bugs.

> 

> That's recursive arithmetic expression parsing in bash, ksh and zsh; if

> the value of a variable is an arithmetic expression (including simply

> another variable name, such as "yo") this is evaluated, which in this

> case means the value of "x" is taken as the value of "yo" which is taken

> as zero. That behaviour is not specified by POSIX, of course.


Right. I only mentioned it because I—as I think we both agree—this behavior is underspecified and probably good as-is. :)

Cheers,
Michael
diff mbox

Patch

diff --git a/src/var.c b/src/var.c
index cc6f7f2..e34f9cf 100644
--- a/src/var.c
+++ b/src/var.c
@@ -353,7 +353,7 @@  lookupvar(const char *name)
 
 intmax_t lookupvarint(const char *name)
 {
-	return atomax(lookupvar(name) ?: nullstr, 0);
+	return atomax(lookupvar(name) ?: "0", 0);
 }