Re: Interesting bug

2022-02-13 Thread Chet Ramey

On 2/12/22 1:24 PM, David Hobach wrote:
I guess 99% of programmers would either expect "Finished" to be printed 
or some syntax error.


Well, 99% of shell programmers will (hopefully ;-) ) put a blank between 
"{" and "echo" in the line


foo="$(testCode)" || {echo "foo";}


Yes, the interesting part is that depending on which space you accidentally 
forget, you'll either get the expected "Finished" or "bad code executed".

foo="$(testCode)" || {echo "foo"; } # --> bad code
foo="$(testCode)" || { echo "foo";} # --> Finished

I guess it closes the function and {echo is interpreted as string or so, 
but that is probably not all (testCode is e.g. never executed).


It's not executed because it's part of a function that's never called.


--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



Re: Interesting bug

2022-02-13 Thread Chet Ramey

On 2/12/22 5:20 PM, David Hobach wrote:

Thanks a lot for the detailed explanations, much appreciated!

So essentially it's no bug - just a rather uncommon choice of keywords.

I still don't agree with that choice since it can be abused to somewhat 
hide code in pull requests to less experienced maintainers, but oh well... 
there's probably enough fun to be had with unicode et al already. And I 
guess the more modern tastes are relatively recent in the history of bash.


You may not agree with the choice of `{' and `}' as reserved words instead
of operators, but that choice is at least 45 years old from the time Bourne
made it. He probably had his own backwards compatibility concerns: scripts
that used `{' and `}' as `normal' unquoted arguments that would have been
broken by making them operators.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



Re: Interesting bug

2022-02-12 Thread David Hobach

Thanks a lot for the detailed explanations, much appreciated!

So essentially it's no bug - just a rather uncommon choice of keywords.

I still don't agree with that choice since it can be abused to somewhat hide 
code in pull requests to less experienced maintainers, but oh well... there's 
probably enough fun to be had with unicode et al already. And I guess the more 
modern tastes are relatively recent in the history of bash.


smime.p7s
Description: S/MIME Cryptographic Signature


Re: Interesting bug

2022-02-12 Thread Ilkka Virta
On Sat, Feb 12, 2022 at 8:25 PM David Hobach  wrote:

> I guess it closes the function and {echo is interpreted as string or so,
> but that is probably not all (testCode is e.g. never executed).
>

Let's see if I get this right.

Removing the irrelevant parts, your code is pretty much this:

func() {
{echo hello;}
{ echo funny stuff
  exit 1
}
}

The key here is that '{' is a keyword, like 'if', or 'do', not an operator
like '('. Which just might be
quite different in other programming languages, but here we are. So,
having '{echo' instead of
'{' is a bit like having 'fiecho' instead of 'fi'. Not relevant for the
syntax, so that the first '}' just after
then ends the function and the block with "echo funny stuff" is on the top
level.

You could have this instead, to the same effect:

func() {
{echo hello
}
if true; then
echo funny stuff
exit 1
fi
fi

Without the explicit "exit", you'd get the syntax error after the "echo
funny stuff" was run. The function itself
is never called, so "echo hello", or whatever there is, never runs.

On the other hand, the shell parses lines in full before doing anything
(and it needs to look if there's a redirection
after the block), so with '} }' or 'fi fi' on one line instead, the syntax
error is caught before the block runs.

For fun, try that with 'fi fi', 'fi; fi', 'fi; xyz' and 'fi xyz' and see
which versions run the block (and try to figure out why)


Re: Interesting bug

2022-02-12 Thread Martin Schulte
Hi David!

> A syntax error would be nice instead.

I see - also from you second answer - that you have some fundamental 
misunderstandings about shell programming:

- Your code will, in case the testCode fails, try execute a program called 
{echo. This is certainly not a good name for a program, but it is not a syntax 
error either.
- Since bash interprets the code the problem with the closing brace is only 
detected when the offending line is passed.

My personal opinion (although I'll probably be bashed here for it ;-) ): Except 
for a very few exceptions like small wrappers avoid writing new shell scripts 
at all - for example use python instead. There are many historically founded 
flaws and odds with shell proramming.

Anyhow, bug-bash@gnu.org is not the right place for these topics, better try 
help-b...@gnu.org.

Best regards

Martin



Re: Interesting bug

2022-02-12 Thread Andreas Schwab
On Feb 12 2022, David Hobach wrote:

> Yes, the interesting part is that depending on which space you accidentally 
> forget, you'll either get the expected "Finished" or "bad code executed".
> foo="$(testCode)" || {echo "foo"; } # --> bad code
> foo="$(testCode)" || { echo "foo";} # --> Finished

There is no forgotten space in the latter line.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."



Re: Interesting bug

2022-02-12 Thread David Hobach

P.S.: Also, if you remove the case/esac from the original example, it'll result 
in a syntax error. So why can the case/esac be used to ignore the syntax error?


smime.p7s
Description: S/MIME Cryptographic Signature


Re: Interesting bug

2022-02-12 Thread David Hobach

I guess 99% of programmers would either expect "Finished" to be printed or some 
syntax error.


Well, 99% of shell programmers will (hopefully ;-) ) put a blank between "{" and 
"echo" in the line

foo="$(testCode)" || {echo "foo";}


Yes, the interesting part is that depending on which space you accidentally forget, you'll either 
get the expected "Finished" or "bad code executed".
foo="$(testCode)" || {echo "foo"; } # --> bad code
foo="$(testCode)" || { echo "foo";} # --> Finished

I guess it closes the function and {echo is interpreted as string or so, but 
that is probably not all (testCode is e.g. never executed).

A syntax error would be nice instead.

Shellcheck at least gets this unless you do something weird and more obvious 
such as
```
#!/bin/bash

function badCode {
echo "bad code executed"
}

function testCode {
#pick some existing file
echo "/etc/passwd"
}

function tfunc {
  local foo=
  foo="$(testCode)" || "{echo" "foo";}
  cat "$foo" || {
badCode
case $? in
 *)
   exit 1
esac
}

echo "Finished."
```

It's also interesting that this - in contrast to the original example - 
triggers a syntax error:
```
#!/bin/bash

function badCode {
echo "bad code executed"
}

function testCode {
#pick some existing file
echo "/etc/passwd"
}

function tfunc {
  local foo=
  foo="$(testCode)" || {echo "foo";}
  cat "$foo" || {
badCode
case $? in
 *)
   exit 1
esac
} } #<-- only difference to the original example

echo "Finished."
```


smime.p7s
Description: S/MIME Cryptographic Signature


Re: Interesting bug

2022-02-12 Thread Léa Gris

On 12/02/2022 at 12:23, David Hobach wrote:


function tfunc {
   local foo=
   foo="$(testCode)" || {echo "foo";}

   ^ Missing space after opening brace

Because the code block is missing a space after the opening brace; the 
opening brace is ignored, but the following closing brace is parsed as 
the end for the tfunc function code block.


The following statements are executed for the global scope since the 
function definition block is closed by the faulty syntax above.

   cat "$foo" || {
     badCode
     case $? in
  *)
    exit 1
     esac
}
}


The bug is in your code.

https://shellcheck.net/ static analysis for shell scripts can help you 
spot such syntax errors.



--
Léa Gris


Re: Interesting bug

2022-02-12 Thread Martin Schulte
Hello David!

> I guess 99% of programmers would either expect "Finished" to be printed or 
> some syntax error.

Well, 99% of shell programmers will (hopefully ;-) ) put a blank between "{" 
and "echo" in the line

foo="$(testCode)" || {echo "foo";}

Best regards

Martin



Interesting bug

2022-02-12 Thread David Hobach

Dear all,

I think I found a rather interesting bug:
```
#!/bin/bash

function badCode {
echo "bad code executed"
}

function testCode {
#pick some existing file, nonexisting works too though
echo "/etc/passwd"
}

function tfunc {
  local foo=
  foo="$(testCode)" || {echo "foo";}
  cat "$foo" || {
badCode
case $? in
 *)
   exit 1
esac
}
}

echo "Finished."
```
(I also attached it.)

I guess 99% of programmers would either expect "Finished" to be printed or some syntax 
error. In fact however the `badCode` function is executed. "Finished" is never executed.
This is a nice one to hide bad code...

Output:
```
cat: '': No such file or directory
bad code executed
```

Affected bash versions:
Debian 11: GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
Fedora 32: GNU bash, version 5.0.17(1)-release (x86_64-redhat-linux-gnu)
(Probably more, these were the only two I tested.)

Happy bug hunting!

Best Regards
David#!/bin/bash

function badCode {
echo "bad code executed"
}

function testCode {
#pick some existing file
echo "/etc/passwd"
}

function tfunc {
  local foo=
  foo="$(testCode)" || {echo "foo";}
  cat "$foo" || { 
badCode
case $? in
 *) 
   exit 1
esac
}
}

echo "Finished."


smime.p7s
Description: S/MIME Cryptographic Signature