BUG #19603: Vuln47: distance_taxicab and distance_chebyshev silently return 0 instead of NaN when a cube coordin
The following bug has been logged on the website:
Bug reference: 19603
Logged by: Yuelin Wang
Email address: 1217816127@qq.com
PostgreSQL version: 19beta2
Operating system: Linux (Ubuntu 24.04, x86_64)
Description:
### Summary
The static helper distance_1D() in contrib/cube/cube.c classifies two
intervals as "left of", "right of", or "intersecting" using direct floating
point comparisons. When a coordinate is NaN, every comparison evaluates to
false, so the interval falls through to the intersecting branch and the
function returns 0.0 instead of NaN. distance_taxicab and distance_chebyshev
call distance_1D per dimension and sum or max the results, so a single NaN
coordinate silently produces a finite, plausible-looking distance instead of
propagating NaN as IEEE 754 arithmetic normally would.
CWE: CWE-1339. Severity: Low.
### PoC
```sql
CREATE EXTENSION cube;
SELECT distance_chebyshev('(nan,nan)'::cube, '(1,1)'::cube);
SELECT distance_chebyshev('(5,5)'::cube, '(1,nan)'::cube);
SELECT distance_taxicab('(nan)'::cube, '(1)'::cube);
```
### Result
Real captured output from the independent verification run:
```
CREATE EXTENSION
distance_chebyshev
--------------------
0
(1 row)
distance_chebyshev
--------------------
4
(1 row)
distance_taxicab
------------------
0
(1 row)
```
### Impact
A database user who stores or queries cube values containing NaN coordinates
can get silently wrong distance results (e.g. 0 instead of NaN) from
distance_taxicab and distance_chebyshev, which can corrupt nearest-neighbor
search results, ranking, or KNN-index-backed queries that rely on these
operators.
Hi,
On Mon, 3 Aug 2026 at 17:21, PG Bug reporting form <noreply@postgresql.org>
wrote:
The following bug has been logged on the website:
Bug reference: 19603
Logged by: Yuelin Wang
Email address: 1217816127@qq.com
PostgreSQL version: 19beta2
Operating system: Linux (Ubuntu 24.04, x86_64)
Description:### Summary
The static helper distance_1D() in contrib/cube/cube.c classifies two
intervals as "left of", "right of", or "intersecting" using direct floating
point comparisons. When a coordinate is NaN, every comparison evaluates to
false, so the interval falls through to the intersecting branch and the
function returns 0.0 instead of NaN. distance_taxicab and
distance_chebyshev
call distance_1D per dimension and sum or max the results, so a single NaN
coordinate silently produces a finite, plausible-looking distance instead
of
propagating NaN as IEEE 754 arithmetic normally would.CWE: CWE-1339. Severity: Low.
### PoC
```sql
CREATE EXTENSION cube;
SELECT distance_chebyshev('(nan,nan)'::cube, '(1,1)'::cube);
SELECT distance_chebyshev('(5,5)'::cube, '(1,nan)'::cube);
SELECT distance_taxicab('(nan)'::cube, '(1)'::cube);
```### Result
Real captured output from the independent verification run:
```
CREATE EXTENSION
distance_chebyshev
--------------------
0
(1 row)distance_chebyshev
--------------------
4
(1 row)distance_taxicab
------------------
0
(1 row)
```### Impact
A database user who stores or queries cube values containing NaN
coordinates
can get silently wrong distance results (e.g. 0 instead of NaN) from
distance_taxicab and distance_chebyshev, which can corrupt nearest-neighbor
search results, ranking, or KNN-index-backed queries that rely on these
operators.
Thanks for the report and repro.
It looks to me like the root is distance_1D(): with a NaN coordinate none of
its comparisons can be true, so it seems to fall through to the overlapping
case and return 0. My first thought was to fix it there and return NaN when
any endpoint is NaN, which seems enough for taxicab and Euclidean (<->),
which
accumulate with +=. Chebyshev needs a bit more, since its running max uses
"d > distance" and NaN > x is false, so I added an explicit NaN check there
too.
Regards,
Ayush