Re: query_int wrongly parses zero-padded input

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

In response to

Responses

Browse pgsql-hackers by date

  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