Re: clang -fsanitize=undefined error in ecpg

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Peter Eisentraut <peter_e(at)gmx(dot)net>
Cc: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: clang -fsanitize=undefined error in ecpg
Date: 2015-03-31 19:40:17
Message-ID: 25477.1427830817@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Peter Eisentraut <peter_e(at)gmx(dot)net> writes:
> With clang -fsanitize=undefined (clang-3.4), I get the following test failure in ecpg
> (it's the only one in the entire tree):

Hm. I don't know why you can't reproduce that in the backend, because
when stepping through DecodeDateTime() on the input
select '19990108foobar'::timestamptz;
I definitely see it shifting 1 left 31 places:

Breakpoint 2, DecodeDateTime (field=<value optimized out>,
ftype=<value optimized out>, nf=2, dtype=0x7ffff6fec168,
tm=0x7ffff6fec170, fsec=0x7ffff6fec1b4, tzp=0x7ffff6fec16c)
at datetime.c:1193
1193 type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
(gdb) n
1194 if (type == UNKNOWN_FIELD)
(gdb) p type
$1 = 31
(gdb) s
1195 type = DecodeSpecial(i, field[i], &val);
(gdb) s
DecodeSpecial (field=1, lowtoken=0x7ffff6febf89 "foobar", val=0x7ffff6febf28)
at datetime.c:3018
3018 {
(gdb) fin
Run till exit from #0 DecodeSpecial (field=1,
lowtoken=0x7ffff6febf89 "foobar", val=0x7ffff6febf28) at datetime.c:3031
DecodeDateTime (field=<value optimized out>, ftype=<value optimized out>,
nf=2, dtype=0x7ffff6fec168, tm=0x7ffff6fec170, fsec=0x7ffff6fec1b4,
tzp=0x7ffff6fec16c) at datetime.c:1196
1196 if (type == IGNORE_DTF)
Value returned is $2 = 31
(gdb) s
1199 tmask = DTK_M(type);
(gdb) p type
$3 = 31
(gdb) s
1200 switch (type)
(gdb) p tmask
$4 = -2147483648

> This patch fixes it:

> -#define DTK_M(t) (0x01 << (t))
> +#define DTK_M(t) ((t) == UNKNOWN_FIELD ? 0 : 0x01 << (t))

Don't like that even a little bit. The intent of the code is perfectly
clear, cf this comment in datetime.h:

* Field types for time decoding.
*
* Can't have more of these than there are bits in an unsigned int
* since these are turned into bit masks during parsing and decoding.

So I think the correct fix is

-#define DTK_M(t) (0x01 << (t))
+#define DTK_M(t) (0x01U << (t))

It looks to me like it doesn't actually matter at the moment, because
anyplace where we apply DTK_M to a value that could be UNKNOWN_FIELD,
we'll immediately after that either return an error or replace the
tmask value with something else. So the lack of portability of this
construction hasn't mattered. But we should fix it in a way that won't
create time bombs for future code changes, and producing a zero mask
from a valid field type code would be a time bomb.

regards, tom lane

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Andrew Dunstan 2015-03-31 19:52:45 Re: How about to have relnamespace and relrole?
Previous Message David Fetter 2015-03-31 19:22:39 Re: Bug fix for missing years in make_date()