Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

print a warning when the return value of a function is checked when errexit is enabled #3095

Open
2 tasks
johnatswoopsrch opened this issue Dec 3, 2024 · 5 comments

Comments

@johnatswoopsrch
Copy link

I would like shellcheck to print a warning when the return value of a function is checked when errexit is enabled.

For details on this problem, see:

For new checks and feature suggestions

Here's a snippet or screenshot that shows the problem:

#!/usr/bin/env bash
set -eu -o pipefail

main() {
    if func ; then
        echo func passed
    else
        echo func failed
    fi
}

func() {
    false
    echo false did not fail
}

main "$@"

Showing the problem:

aMBP:~> /tmp/try
false did not fail
func passed
aMBP:~>

Here's what shellcheck currently says:

It says nothing.

aMBP:~> shellcheck /tmp/try
aMBP:~>

Here's what I wanted or expected to see:

WARNING: checking the return value of a function disables errexit inside the function
@wileyhy
Copy link

wileyhy commented Dec 9, 2024 via email

@wileyhy
Copy link

wileyhy commented Dec 9, 2024 via email

@johnatswoopsrch
Copy link
Author

@wileyhy Yes, that would be the case. The links I provided explain the unexpected behavior.

@wileyhy
Copy link

wileyhy commented Dec 12, 2024 via email

@johnatswoopsrch
Copy link
Author

I would not expand this to compound commands in general, although maybe there are patterns that could be caught. That seems like a bigger and more complicated issue.

I'm not sure what accurate warning text would be. That might depend on exactly what you're able to detect.

I know functions are a problem in these cases, although I don't know if you're able to detect it or not. Not having errexit active in functions within a script that has it active is not intuitive, and a source of errors. I've wasted considerable time chasing a few of these problems, before getting it burned into my brain to watch for it. I'd like to save others that pain if possible.

It seems remediation is not very straight forward. My research and testing seems to indicate there are multiple alternatives to getting information out of functions without running them in compound commands, but none of them ideal. As well, some very simple cases work OK if you're careful.

  1. Only check the return value from functions if you're sure there are no chances of unexpected errors that errexit would catch. Maybe single-command functions could work?
  2. Otherwise, do not use return values from functions. If you're checking the return value, you've disabled errexit. If you have a real error, that justifies exiting the script, just use exit. The only case where checking the return value of a function is safe is if you've manually made every line safe from possible errors.
  3. If you need to pass any value back from the function, you can
    2a) use a global variable (and of course don't recurse)
    2b) use a unique output file
    2c) save the output to a variable, by setting errexit in the function, and call the function in a subshell, ie output=$(func).
#!/usr/bin/env bash
set -eu -o pipefail

funcgood() {
    set -e
    echo yes
}

funcbad() {
    set -e
    false
    echo yes
}

set -x
value=$(funcgood)
echo value for funcgood is $value

value2=$(funcbad)
echo value for funcbad is $value2
bash-5.2$ /tmp/try2
++ funcgood
++ set -e
++ echo yes
+ value=yes
+ echo value for funcgood is yes
value for funcgood is yes
++ funcbad
++ false
++ echo yes
+ value=yes
+ echo value for funcbad is yes
value for funcbad is yes
bash-5.2$ /tmp/try2
++ funcgood
++ set -e
++ echo yes
+ value=yes
+ echo value for funcgood is yes
value for funcgood is yes
++ funcbad
++ set -e
++ false
+ value2=
bash-5.2$

If you are able to detect the issue, then what additional information to reference is tricky too, as there is no simple answer it seems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants