Skip to content

Commit 221e92f

Browse files
committed
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings (case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity", "-infinity". However, pre-C99 systems might accept only some or none of these, and apparently Windows still doesn't accept "inf". To avoid surprising cross-platform behavioral differences, manually check for each of these spellings if strtod() fails. We were previously handling just "infinity" and "-infinity" that way, but since C99 is most of the world now, it seems likely that applications are expecting all these spellings to work. Per bug #8355 from Basil Peace. It turns out this fix won't actually resolve his problem, because Python isn't being this careful; but that doesn't mean we shouldn't be.
1 parent 706f9dd commit 221e92f

File tree

1 file changed

+75
-23
lines changed

1 file changed

+75
-23
lines changed

src/backend/utils/adt/float.c

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,7 @@ is_infinite(double val)
176176

177177

178178
/*
179-
* float4in - converts "num" to float
180-
* restricted syntax:
181-
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
182-
* where <sp> is a space, digit is 0-9,
183-
* <exp> is "e" or "E" followed by an integer.
179+
* float4in - converts "num" to float4
184180
*/
185181
Datum
186182
float4in(PG_FUNCTION_ARGS)
@@ -197,6 +193,10 @@ float4in(PG_FUNCTION_ARGS)
197193
*/
198194
orig_num = num;
199195

196+
/* skip leading whitespace */
197+
while (*num != '\0' && isspace((unsigned char) *num))
198+
num++;
199+
200200
/*
201201
* Check for an empty-string input to begin with, to avoid the vagaries of
202202
* strtod() on different platforms.
@@ -207,10 +207,6 @@ float4in(PG_FUNCTION_ARGS)
207207
errmsg("invalid input syntax for type real: \"%s\"",
208208
orig_num)));
209209

210-
/* skip leading whitespace */
211-
while (*num != '\0' && isspace((unsigned char) *num))
212-
num++;
213-
214210
errno = 0;
215211
val = strtod(num, &endptr);
216212

@@ -220,9 +216,14 @@ float4in(PG_FUNCTION_ARGS)
220216
int save_errno = errno;
221217

222218
/*
223-
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
224-
* platforms support that yet (and some accept them but set ERANGE
225-
* anyway...) Therefore, we check for these inputs ourselves.
219+
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
220+
* but not all platforms support all of these (and some accept them
221+
* but set ERANGE anyway...) Therefore, we check for these inputs
222+
* ourselves if strtod() fails.
223+
*
224+
* Note: C99 also requires hexadecimal input as well as some extended
225+
* forms of NaN, but we consider these forms unportable and don't try
226+
* to support them. You can use 'em if your strtod() takes 'em.
226227
*/
227228
if (pg_strncasecmp(num, "NaN", 3) == 0)
228229
{
@@ -234,11 +235,31 @@ float4in(PG_FUNCTION_ARGS)
234235
val = get_float4_infinity();
235236
endptr = num + 8;
236237
}
238+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
239+
{
240+
val = get_float4_infinity();
241+
endptr = num + 9;
242+
}
237243
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
238244
{
239245
val = -get_float4_infinity();
240246
endptr = num + 9;
241247
}
248+
else if (pg_strncasecmp(num, "inf", 3) == 0)
249+
{
250+
val = get_float4_infinity();
251+
endptr = num + 3;
252+
}
253+
else if (pg_strncasecmp(num, "+inf", 4) == 0)
254+
{
255+
val = get_float4_infinity();
256+
endptr = num + 4;
257+
}
258+
else if (pg_strncasecmp(num, "-inf", 4) == 0)
259+
{
260+
val = -get_float4_infinity();
261+
endptr = num + 4;
262+
}
242263
else if (save_errno == ERANGE)
243264
{
244265
/*
@@ -287,6 +308,11 @@ float4in(PG_FUNCTION_ARGS)
287308
val = get_float4_infinity();
288309
endptr = num + 8;
289310
}
311+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
312+
{
313+
val = get_float4_infinity();
314+
endptr = num + 9;
315+
}
290316
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
291317
{
292318
val = -get_float4_infinity();
@@ -382,10 +408,6 @@ float4send(PG_FUNCTION_ARGS)
382408

383409
/*
384410
* float8in - converts "num" to float8
385-
* restricted syntax:
386-
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
387-
* where <sp> is a space, digit is 0-9,
388-
* <exp> is "e" or "E" followed by an integer.
389411
*/
390412
Datum
391413
float8in(PG_FUNCTION_ARGS)
@@ -402,6 +424,10 @@ float8in(PG_FUNCTION_ARGS)
402424
*/
403425
orig_num = num;
404426

427+
/* skip leading whitespace */
428+
while (*num != '\0' && isspace((unsigned char) *num))
429+
num++;
430+
405431
/*
406432
* Check for an empty-string input to begin with, to avoid the vagaries of
407433
* strtod() on different platforms.
@@ -412,10 +438,6 @@ float8in(PG_FUNCTION_ARGS)
412438
errmsg("invalid input syntax for type double precision: \"%s\"",
413439
orig_num)));
414440

415-
/* skip leading whitespace */
416-
while (*num != '\0' && isspace((unsigned char) *num))
417-
num++;
418-
419441
errno = 0;
420442
val = strtod(num, &endptr);
421443

@@ -425,9 +447,14 @@ float8in(PG_FUNCTION_ARGS)
425447
int save_errno = errno;
426448

427449
/*
428-
* C99 requires that strtod() accept NaN and [-]Infinity, but not all
429-
* platforms support that yet (and some accept them but set ERANGE
430-
* anyway...) Therefore, we check for these inputs ourselves.
450+
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
451+
* but not all platforms support all of these (and some accept them
452+
* but set ERANGE anyway...) Therefore, we check for these inputs
453+
* ourselves if strtod() fails.
454+
*
455+
* Note: C99 also requires hexadecimal input as well as some extended
456+
* forms of NaN, but we consider these forms unportable and don't try
457+
* to support them. You can use 'em if your strtod() takes 'em.
431458
*/
432459
if (pg_strncasecmp(num, "NaN", 3) == 0)
433460
{
@@ -439,11 +466,31 @@ float8in(PG_FUNCTION_ARGS)
439466
val = get_float8_infinity();
440467
endptr = num + 8;
441468
}
469+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
470+
{
471+
val = get_float8_infinity();
472+
endptr = num + 9;
473+
}
442474
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
443475
{
444476
val = -get_float8_infinity();
445477
endptr = num + 9;
446478
}
479+
else if (pg_strncasecmp(num, "inf", 3) == 0)
480+
{
481+
val = get_float8_infinity();
482+
endptr = num + 3;
483+
}
484+
else if (pg_strncasecmp(num, "+inf", 4) == 0)
485+
{
486+
val = get_float8_infinity();
487+
endptr = num + 4;
488+
}
489+
else if (pg_strncasecmp(num, "-inf", 4) == 0)
490+
{
491+
val = -get_float8_infinity();
492+
endptr = num + 4;
493+
}
447494
else if (save_errno == ERANGE)
448495
{
449496
/*
@@ -492,6 +539,11 @@ float8in(PG_FUNCTION_ARGS)
492539
val = get_float8_infinity();
493540
endptr = num + 8;
494541
}
542+
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
543+
{
544+
val = get_float8_infinity();
545+
endptr = num + 9;
546+
}
495547
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
496548
{
497549
val = -get_float8_infinity();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy