-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix representation of negative non-base-10 numbers
Simple reproducer: $ typeset -si16 n=-12 $ echo $n 16#fffffffffffffff4 Expected output: -16#c The base-16 representation is incorrectly treated as unsigned (and also as long integer -li, though it was declared as -si -- e.g. 'typeset -sui 16 n=-12' correctly outputs 16#fff4). This behaviour is clearly incorrect in two ways. Both the signedness and the type should match in the output. With less obvious cases, this can be very confusing, e.g.: $ typeset -li20 n=-20#j12 $ echo $n 20#b53bjh07be4cjje Expected output: -20#j12 Analysis: nv_getval(), the central function to render a variable's value as a string, calls libast's fmtbase() to render numbers of any type (src/lib/libast/string/fmtbase.c). When the base is 10 and the prefix is not shown, this simply calls fmtint (fmtint.c) which is a performance-optimised function to render base-10 integers, and all is well. But if a base is explicitly specified (b != 0), then if the base is 10, fmtint() is always called with unsign==1, or if the base is other than 10, fmtbase() always tells sfsprintf() to treat the value as unsigned (using the %u formatter). This is the problem. It was clearly done this way on purpose, but it's also clearly wrong. I also made the following observations: (1) ksh is the only user of the fmtbase() function; even in the old complete AST toolset, nothing else calls fmtbase(). So we don't need to worry about backward compatibility here. (2) fmtint() has only ever been called via fmtbase(), though it is publicly declared in ast.h. (3) fmtbase() is called in 10 places in the ksh code. Only one of them, the one in nv_getval(), possibly involves a non-10 base. The rest of them just use fmtint() via fmtbase(). (4) fmtbase() is inefficient. It uses a string buffer returned by fmtbuf(), not an Sfio stream buffer. This is efficient for fmtint() which stores output directly in memory. But for a non-10 base, fmtbase() calls sfsprintf() (see sfio/sfprintf.c) which opens a temporary Sfio stream, calls sfprintf(), copies the Sfio stream buffer contents to the string buffer, then closes the stream. It should be faster to use Sfio directly. So, with all that taken into consideration, this commit simplifies the eight fmtbase() calls with a known base of 10 to equivalent fmtint() calls, and handles the ninth case directly in nv_getval() using the sh.strbuf stream buffer pre-opened in init.c. Handling signedness correctly in nv_getval() is trivial, because sfprintf() does the correct thing if the correct d or u formatter is used. With these changes, the incorrect fmtbase() function is now unused, and is therefore deleted. Relevant documentation updates are made. Thanks to Daniel Douglas (@ormaaj) for the bug report. Resolves: #696
- Loading branch information
Showing
18 changed files
with
65 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.