Skip to content

Commit e348e7a

Browse files
committed
Prevent infinity and NaN in jsonb/plperl transform
jsonb uses numeric internally, and numeric can store NaN, but that is not allowed by jsonb on input, so we shouldn't store it. Also prevent infinity to get a consistent error message. (numeric input would reject infinity anyway.) Reported-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
1 parent f7df804 commit e348e7a

File tree

5 files changed

+102
-6
lines changed

5 files changed

+102
-6
lines changed

contrib/jsonb_plperl/expected/jsonb_plperl.out

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
3939
1
4040
(1 row)
4141

42+
CREATE FUNCTION testInf() RETURNS jsonb
43+
LANGUAGE plperl
44+
TRANSFORM FOR TYPE jsonb
45+
AS $$
46+
$val = 0 + 'Inf';
47+
return $val;
48+
$$;
49+
SELECT testInf();
50+
ERROR: cannot convert infinity to jsonb
51+
CONTEXT: PL/Perl function "testinf"
52+
CREATE FUNCTION testNaN() RETURNS jsonb
53+
LANGUAGE plperl
54+
TRANSFORM FOR TYPE jsonb
55+
AS $$
56+
$val = 0 + 'NaN';
57+
return $val;
58+
$$;
59+
SELECT testNaN();
60+
ERROR: cannot convert NaN to jsonb
61+
CONTEXT: PL/Perl function "testnan"
4262
-- this revealed a bug in the original implementation
4363
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
4464
LANGUAGE plperl
@@ -71,7 +91,7 @@ SELECT roundtrip('1');
7191
(1 row)
7292

7393
SELECT roundtrip('1E+131071');
74-
ERROR: cannot convert infinite value to jsonb
94+
ERROR: cannot convert infinity to jsonb
7595
CONTEXT: PL/Perl function "roundtrip"
7696
SELECT roundtrip('-1');
7797
roundtrip
@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
207227

208228
\set VERBOSITY terse \\ -- suppress cascade details
209229
DROP EXTENSION plperl CASCADE;
210-
NOTICE: drop cascades to 6 other objects
230+
NOTICE: drop cascades to 8 other objects

contrib/jsonb_plperl/expected/jsonb_plperlu.out

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ SELECT testSVToJsonb();
3939
1
4040
(1 row)
4141

42+
CREATE FUNCTION testInf() RETURNS jsonb
43+
LANGUAGE plperlu
44+
TRANSFORM FOR TYPE jsonb
45+
AS $$
46+
$val = 0 + 'Inf';
47+
return $val;
48+
$$;
49+
SELECT testInf();
50+
ERROR: cannot convert infinity to jsonb
51+
CONTEXT: PL/Perl function "testinf"
52+
CREATE FUNCTION testNaN() RETURNS jsonb
53+
LANGUAGE plperlu
54+
TRANSFORM FOR TYPE jsonb
55+
AS $$
56+
$val = 0 + 'NaN';
57+
return $val;
58+
$$;
59+
SELECT testNaN();
60+
ERROR: cannot convert NaN to jsonb
61+
CONTEXT: PL/Perl function "testnan"
4262
-- this revealed a bug in the original implementation
4363
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
4464
LANGUAGE plperlu
@@ -71,7 +91,7 @@ SELECT roundtrip('1');
7191
(1 row)
7292

7393
SELECT roundtrip('1E+131071');
74-
ERROR: cannot convert infinite value to jsonb
94+
ERROR: cannot convert infinity to jsonb
7595
CONTEXT: PL/Perl function "roundtrip"
7696
SELECT roundtrip('-1');
7797
roundtrip
@@ -207,4 +227,4 @@ SELECT roundtrip('{"1": {"2": [3, 4, 5]}, "2": 3}');
207227

208228
\set VERBOSITY terse \\ -- suppress cascade details
209229
DROP EXTENSION plperlu CASCADE;
210-
NOTICE: drop cascades to 6 other objects
230+
NOTICE: drop cascades to 8 other objects

contrib/jsonb_plperl/jsonb_plperl.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,22 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
211211
{
212212
double nval = SvNV(in);
213213

214+
/*
215+
* jsonb doesn't allow infinity or NaN (per JSON
216+
* specification), but the numeric type that is used for the
217+
* storage accepts NaN, so we have to prevent it here
218+
* explicitly. We don't really have to check for isinf()
219+
* here, as numeric doesn't allow it and it would be caught
220+
* later, but it makes for a nicer error message.
221+
*/
214222
if (isinf(nval))
215223
ereport(ERROR,
216-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
217-
(errmsg("cannot convert infinite value to jsonb"))));
224+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
225+
(errmsg("cannot convert infinity to jsonb"))));
226+
if (isnan(nval))
227+
ereport(ERROR,
228+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
229+
(errmsg("cannot convert NaN to jsonb"))));
218230

219231
out.type = jbvNumeric;
220232
out.val.numeric =

contrib/jsonb_plperl/sql/jsonb_plperl.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ $$;
3434
SELECT testSVToJsonb();
3535

3636

37+
CREATE FUNCTION testInf() RETURNS jsonb
38+
LANGUAGE plperl
39+
TRANSFORM FOR TYPE jsonb
40+
AS $$
41+
$val = 0 + 'Inf';
42+
return $val;
43+
$$;
44+
45+
SELECT testInf();
46+
47+
48+
CREATE FUNCTION testNaN() RETURNS jsonb
49+
LANGUAGE plperl
50+
TRANSFORM FOR TYPE jsonb
51+
AS $$
52+
$val = 0 + 'NaN';
53+
return $val;
54+
$$;
55+
56+
SELECT testNaN();
57+
58+
3759
-- this revealed a bug in the original implementation
3860
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
3961
LANGUAGE plperl

contrib/jsonb_plperl/sql/jsonb_plperlu.sql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ $$;
3434
SELECT testSVToJsonb();
3535

3636

37+
CREATE FUNCTION testInf() RETURNS jsonb
38+
LANGUAGE plperlu
39+
TRANSFORM FOR TYPE jsonb
40+
AS $$
41+
$val = 0 + 'Inf';
42+
return $val;
43+
$$;
44+
45+
SELECT testInf();
46+
47+
48+
CREATE FUNCTION testNaN() RETURNS jsonb
49+
LANGUAGE plperlu
50+
TRANSFORM FOR TYPE jsonb
51+
AS $$
52+
$val = 0 + 'NaN';
53+
return $val;
54+
$$;
55+
56+
SELECT testNaN();
57+
58+
3759
-- this revealed a bug in the original implementation
3860
CREATE FUNCTION testRegexpResultToJsonb() RETURNS jsonb
3961
LANGUAGE plperlu

0 commit comments

Comments
 (0)