Bug 235589 - sh(1): LINENO is unset in shell arithmetic
Summary: sh(1): LINENO is unset in shell arithmetic
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 12.0-STABLE
Hardware: Any Any
: --- Affects Some People
Assignee: Jilles Tjoelker
Keywords: needs-qa
Depends on:
Reported: 2019-02-07 23:01 UTC by Martijn Dekker
Modified: 2019-09-08 21:31 UTC (History)
3 users (show)

See Also:
koobs: mfc-stable12?
koobs: mfc-stable11?

Proposed fix patch (2.72 KB, patch)
2019-08-02 02:42 UTC, Paco Pascal
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martijn Dekker 2019-02-07 23:01:32 UTC
In sh(1), the LINENO variable (currently executed line number) is always zero when it is read as part of a shell arithmetic expression.

For instance:

$ echo $LINENO $((LINENO)) $(($LINENO))
108 0 108

Expected: 3 times "108" (or whatever the current line number is)

Note that $(($LINENO)) does work because it expands LINENO as a normal shell expansion before invoking the arithmetic subsystem. However, $((LINENO)) should be equivalent as it is for all other variables.

Another manifestation of the bug is:

$ set -u
$ echo $((LINENO))
-sh: arithmetic expression: variable not set: "LINENO"
Comment 1 Paco Pascal 2019-08-02 02:42:15 UTC
Created attachment 206211 [details]
Proposed fix patch

This is my first attempt at submitting a patch to FreeBSD. I'm not sure if it's good practice to submit a potential patch directly to the bug report or to first have it reviewed elsewhere such as the mailing lists.
Comment 2 Kubilay Kocak freebsd_committer freebsd_triage 2019-09-05 11:32:06 UTC
(In reply to Paco Pascal from comment #1)

Proposing patches is always welcome with or without having it discussed or reviewed prior. Having said that, it can and does help, usually to improve the proposed patch, if one can get some feedback on it.

@Jilles (CC'd), with experience in this area of the tree, may know what to do with this
Comment 3 Jilles Tjoelker freebsd_committer 2019-09-08 21:29:42 UTC
I like that this does not slow down the main execution loop much, since it only does the conversion from integer to string when LINENO is referenced.

This part could be slightly less magic by making a fixed struct var for LINENO (like HISTSIZE, IFS, MAIL, MAILPATH, etc.). This fixed struct can also point to a sufficiently large buffer "LINENO=1\0\0\0\0\0\0\0\0\0\0".

I would like to see this new mechanism used instead of the old VSLINENO mechanism (so there aren't two separate mechanisms for $LINENO and $((LINENO))).

Given that this will subtly change LINENO values anyway (try expanding LINENO twice in different lines of a word spanning multiple lines), I think it would make more sense to make it more like other shells do, reading the line number at the start of a command containing expansions (NCMD/NCASE/NFOR).

With this, it should be possible to set PS4='$LINENO+ ' and see the script's line numbers in set -x output.

You can compare https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=5bb39bb1995cb12d8da76b1d482df9be1acc2eb4 which is a similar implementation for dash (another Almquist variant) but I don't think there will be much benefit in copying code from there.