Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [BUG] printf truncates large values
- X-seq: zsh-workers 42332
- From: Peter Stephenson <p.stephenson@xxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: [BUG] printf truncates large values
- Date: Tue, 30 Jan 2018 18:30:42 +0000
- Cms-type: 201P
- Dkim-filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20180130183047euoutp0177f78c7dccd67514caa8013027df91da~OqgFY5ykp0216302163euoutp01U
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1517337047; bh=ToelrdvxTcl7olMIEx0Nhw2NPYFIo0nrCeYQ5yvuczs=; h=Date:From:To:Subject:In-reply-to:References:From; b=A5KMGvr4j1G9fvUPO6cPBdzdaEQFOKSt+1TgqiS+n6d2PqttT7SxRF6YKz+YLw4l5 /q3UqmaqOMFRwsRPd+4ra96aA4l/pBgq8pVjYgUO0l7mnFdQFB8y+MtOWCmzfDRwAb /PM3hiD5l1AEd08qR+gBEoVQYhoJH7QlGexG095w=
- In-reply-to: <20180130164021.GA521@cventin.lip.ens-lyon.fr>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- List-unsubscribe: <mailto:zsh-workers-unsubscribe@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- Organization: Samsung Cambridge Solution Centre
- References: <CGME20180130164832epcas1p1460baafa538692bcc1f9b169f00f0bc5@epcas1p1.samsung.com> <20180130164021.GA521@cventin.lip.ens-lyon.fr>
On Tue, 30 Jan 2018 17:40:21 +0100
Vincent Lefevre <vincent@xxxxxxxxxx> 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)
Messages sorted by:
Reverse Date,
Date,
Thread,
Author