Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7769fc0

Browse files
committed
Fix behavior when converting a float infinity to numeric.
float8_numeric() and float4_numeric() failed to consider the possibility that the input is an IEEE infinity. The results depended on the platform-specific behavior of sprintf(): on most platforms you'd get something like ERROR: invalid input syntax for type numeric: "inf" but at least on Windows it's possible for the conversion to succeed and deliver a finite value (typically 1), due to a nonstandard output format from sprintf and lack of syntax error checking in these functions. Since our numeric type lacks the concept of infinity, a suitable conversion is impossible; the best thing to do is throw an explicit error before letting sprintf do its thing. While at it, let's use snprintf not sprintf. Overrunning the buffer should be impossible if sprintf does what it's supposed to, but this is cheap insurance against a stack smash if it doesn't. Problem reported by Taiki Kondo. Patch by me based on fix suggestion from KaiGai Kohei. Back-patch to all supported branches. Discussion: https://postgr.es/m/12A9442FBAE80D4E8953883E0B84E088C8C7A2@BPXM01GP.gisp.nec.co.jp
1 parent 28e0727 commit 7769fc0

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

src/backend/utils/adt/numeric.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -3143,7 +3143,12 @@ float8_numeric(PG_FUNCTION_ARGS)
31433143
if (isnan(val))
31443144
PG_RETURN_NUMERIC(make_result(&const_nan));
31453145

3146-
sprintf(buf, "%.*g", DBL_DIG, val);
3146+
if (isinf(val))
3147+
ereport(ERROR,
3148+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3149+
errmsg("cannot convert infinity to numeric")));
3150+
3151+
snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
31473152

31483153
init_var(&result);
31493154

@@ -3209,7 +3214,12 @@ float4_numeric(PG_FUNCTION_ARGS)
32093214
if (isnan(val))
32103215
PG_RETURN_NUMERIC(make_result(&const_nan));
32113216

3212-
sprintf(buf, "%.*g", FLT_DIG, val);
3217+
if (isinf(val))
3218+
ereport(ERROR,
3219+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3220+
errmsg("cannot convert infinity to numeric")));
3221+
3222+
snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
32133223

32143224
init_var(&result);
32153225

src/test/regress/expected/numeric.out

+21
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,27 @@ SELECT * FROM fract_only;
708708
(6 rows)
709709

710710
DROP TABLE fract_only;
711+
-- Check inf/nan conversion behavior
712+
SELECT 'NaN'::float8::numeric;
713+
numeric
714+
---------
715+
NaN
716+
(1 row)
717+
718+
SELECT 'Infinity'::float8::numeric;
719+
ERROR: cannot convert infinity to numeric
720+
SELECT '-Infinity'::float8::numeric;
721+
ERROR: cannot convert infinity to numeric
722+
SELECT 'NaN'::float4::numeric;
723+
numeric
724+
---------
725+
NaN
726+
(1 row)
727+
728+
SELECT 'Infinity'::float4::numeric;
729+
ERROR: cannot convert infinity to numeric
730+
SELECT '-Infinity'::float4::numeric;
731+
ERROR: cannot convert infinity to numeric
711732
-- Simple check that ceil(), floor(), and round() work correctly
712733
CREATE TABLE ceil_floor_round (a numeric);
713734
INSERT INTO ceil_floor_round VALUES ('-5.5');

src/test/regress/sql/numeric.sql

+8
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,14 @@ INSERT INTO fract_only VALUES (8, '0.00017');
655655
SELECT * FROM fract_only;
656656
DROP TABLE fract_only;
657657

658+
-- Check inf/nan conversion behavior
659+
SELECT 'NaN'::float8::numeric;
660+
SELECT 'Infinity'::float8::numeric;
661+
SELECT '-Infinity'::float8::numeric;
662+
SELECT 'NaN'::float4::numeric;
663+
SELECT 'Infinity'::float4::numeric;
664+
SELECT '-Infinity'::float4::numeric;
665+
658666
-- Simple check that ceil(), floor(), and round() work correctly
659667
CREATE TABLE ceil_floor_round (a numeric);
660668
INSERT INTO ceil_floor_round VALUES ('-5.5');

0 commit comments

Comments
 (0)