zsh-workers
 help / color / mirror / code / Atom feed
* [BUG] printf truncates large values
@ 2018-01-30 16:40 ` Vincent Lefevre
  2018-01-30 18:30   ` Peter Stephenson
  0 siblings, 1 reply; 2+ messages in thread
From: Vincent Lefevre @ 2018-01-30 16:40 UTC (permalink / raw)
  To: zsh-workers

On a 64-bit x86_64 machine, with zsh 5.4.2:

cventin% printf "%x\n" 10865468317030705979
zsh: number truncated after 19 digits: 10865468317030705979
f1430962f7cd785

There's no reason to truncate the value on a 64-bit machine!

The printf from GNU coreutils is correct:

cventin% /usr/bin/printf "%x\n" 10865468317030705979
96c9e5dddae06b3b

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [BUG] printf truncates large values
  2018-01-30 16:40 ` [BUG] printf truncates large values Vincent Lefevre
@ 2018-01-30 18:30   ` Peter Stephenson
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Stephenson @ 2018-01-30 18:30 UTC (permalink / raw)
  To: zsh-workers

On Tue, 30 Jan 2018 17:40:21 +0100
Vincent Lefevre <vincent@vinc17.net> wrote:
> On a 64-bit x86_64 machine, with zsh 5.4.2:
> 
> cventin% printf "%x\n" 10865468317030705979
> zsh: number truncated after 19 digits: 10865468317030705979
> f1430962f7cd785

This is not because of the standard integer representation, it relates
to whatever type we picked for zlong (and the corresponding unsigned
type, zulong, which has the same length).

The problem is this goes through math evaluation (mathevali())
regardless of the fact that it's a constant, so becomes a zlong.  This
means we lose track of the fact it's actually unsigned.

The only easyish fix is to scan for a constant and avoid the mathevali()
in that case.  So I copied and adapted zstrtol_underscore() to do that.
Anything more requires propagating full-length unsigned values
separately through the integer code, which is a large undertaking not
entirely without its own problems.

pws

diff --git a/Src/builtin.c b/Src/builtin.c
index 0211f27..fb59738 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5243,7 +5243,10 @@ bin_print(char *name, char **args, Options ops, int func)
  		    	*d++ = 'l';
 #endif
 		    	*d++ = 'l', *d++ = *c, *d = '\0';
-			zulongval = (curarg) ? mathevali(curarg) : 0;
+			if (!curarg)
+			    zulongval = (zulong)0;
+			else if (!zstrtoul_underscore(curarg, &zulongval))
+			    zulongval = mathevali(curarg);
 			if (errflag) {
 			    zulongval = 0;
 			    errflag &= ~ERRFLAG_ERROR;
diff --git a/Src/utils.c b/Src/utils.c
index 74fdac3..3b589aa 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2455,6 +2455,67 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore)
     return neg ? -(zlong)calc : (zlong)calc;
 }
 
+/*
+ * If s represents a complete unsigned integer (and nothing else)
+ * return 1 and set retval to the value.  Otherwise return 0.
+ *
+ * Underscores are always allowed.
+ *
+ * Sensitive to OCTAL_ZEROES.
+ */
+
+/**/
+mod_export int
+zstrtoul_underscore(const char *s, zulong *retval)
+{
+    zulong calc = 0, newcalc = 0, base;
+
+    if (*s == '+')
+	s++;
+
+    if (*s != '0')
+	base = 10;
+    else if (*++s == 'x' || *s == 'X')
+	base = 16, s++;
+    else if (*s == 'b' || *s == 'B')
+	base = 2, s++;
+    else
+	base = isset(OCTALZEROES) ? 8 : 10;
+    if (base < 2 || base > 36) {
+	return 0;
+    } else if (base <= 10) {
+	for (; (*s >= '0' && *s < ('0' + base)) ||
+		 *s == '_'; s++) {
+	    if (*s == '_')
+		continue;
+	    newcalc = calc * base + *s - '0';
+	    if (newcalc < calc)
+	    {
+		return 0;
+	    }
+	    calc = newcalc;
+	}
+    } else {
+	for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
+	     || (*s >= 'A' && *s < ('A' + base - 10))
+	     || *s == '_'; s++) {
+	    if (*s == '_')
+		continue;
+	    newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
+	    if (newcalc < calc)
+	    {
+		return 0;
+	    }
+	    calc = newcalc;
+	}
+    }
+
+    if (*s)
+	return 0;
+    *retval = calc;
+    return 1;
+}
+
 /**/
 mod_export int
 setblock_fd(int turnonblocking, int fd, long *modep)


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-01-30 18:41 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20180130164832epcas1p1460baafa538692bcc1f9b169f00f0bc5@epcas1p1.samsung.com>
2018-01-30 16:40 ` [BUG] printf truncates large values Vincent Lefevre
2018-01-30 18:30   ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).