| From: | Manu <manuelreyesbravo(at)gmail(dot)com> |
|---|---|
| To: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
| Cc: | Marko Grujic <marko(dot)grujic(at)enterprisedb(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: query_int wrongly parses zero-padded input |
| Date: | 2026-10-18 02:10:29 |
| Message-ID: | 179228942964.2042185.8242333686786702114@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> writes:
> Oh, that's an excellent point: if we did want to go the direction of
> exposing strtol's full behavior, we'd need to make the code check
> that strtol ate the whole input, which it does not today. I think
> it's unnecessary to add such a check if we switch to base 10
> (maybe I'm wrong?).
I think you're right, and I measured it rather than reason about it. I
instrumented the one strtol() call in _int_bool.c and swept every byte
0x01-0xFF in seven operand positions (SQL_ASCII, so high bytes arrive
unconverted): the only bytes that ever reach the buffer are '-' and '0'-'9',
the same under base 0 and base 10. Everything else -- x, b, o, e, '+', '_',
'.', and all of 0x80-0xFF -- is a syntax error before strtol() is called. So
strtol() is always handed an optional sign followed by decimal digits, and
under base 10 it consumes all of them; there is no trailing input for an "ate
the whole input" check to catch.
To put a number on it, I ran 72,222,250 operand buffers (the short ones
exhaustively, the longer ones sampled) through strtol() with an end-pointer
check. Under base 10 exactly one is not consumed whole: the lone "-", where
strtol() returns 0 and advances nothing, so '1&-' parses as '1 & 0'. Under
base 0, 23,620,854 of them are not -- every leading-zero operand that reaches
an 8 or 9, which is the bug. A cross-check against the instrumented server
matched on all 29,430 sampled buffers (buffer, endptr, value, errno and
output), so this is the server's behavior, not a model's.
Two things so "nothing left to guard" isn't overstated. The existing
errno/int32 range check still earns its keep: an overflowing operand like
'99999999999' is consumed whole and rejected there, not through endptr. And
the lone "-" is pre-existing and base-independent -- base 0 accepts it as 0
today too; an end-pointer check would reject it, but that is a separate
question from the base, so I would not fold it into this patch.
regards,
Manu
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Tom Lane | 2026-10-18 02:35:00 | Re: query_int wrongly parses zero-padded input |
| Previous Message | Tom Lane | 2026-10-18 01:44:56 | Re: query_int wrongly parses zero-padded input |