diff --git a/XS.xs b/XS.xs index 3c32e50..419e07e 100644 --- a/XS.xs +++ b/XS.xs @@ -4499,12 +4499,14 @@ decode_json (pTHX_ SV *string, JSON *json, STRLEN *offset_return, SV *typesv) #endif croak ("%s, at character offset %d (before \"%s\")", dec.err, - (int)ptr_to_index (aTHX_ string, dec.cur-SvPVX(string)), + (int)ptr_to_index (aTHX_ string, dec.cur - SvPVX(string)), dec.cur != dec.end ? SvPV_nolen (uni) : "(end of string)"); } - if (!(dec.json.flags & F_ALLOW_NONREF) && json_nonref(aTHX_ sv)) + if (!(dec.json.flags & F_ALLOW_NONREF) && json_nonref(aTHX_ sv)) { + SvREFCNT_dec (sv); croak ("JSON text must be an object or array (but found number, string, true, false or null, use allow_nonref to allow this)"); + } if (UNLIKELY(converted && !(converted - 1))) /* with BOM, and UTF8 was not set */ json->flags &= ~F_UTF8; diff --git a/xt/leaktrace.t b/xt/leaktrace.t index dba9d6b..7a35746 100644 --- a/xt/leaktrace.t +++ b/xt/leaktrace.t @@ -4,7 +4,7 @@ use strict; use constant HAS_LEAKTRACE => eval{ require Test::LeakTrace }; -use Test::More HAS_LEAKTRACE ? (tests => 1) : (skip_all => 'require Test::LeakTrace'); +use Test::More HAS_LEAKTRACE ? (tests => 4) : (skip_all => 'require Test::LeakTrace'); use Test::LeakTrace; use Cpanel::JSON::XS; @@ -22,3 +22,23 @@ leaks_cmp_ok{ $js->encode ( bless { k => 1 }, Temp1:: ); } '<', 1; + +# leak on allow_nonref croak, GH 206 +leaks_cmp_ok{ + eval { decode_json('"asdf"') }; + #print $@; +} '<', 1; + +# illegal unicode croak +leaks_cmp_ok{ + eval { decode_json("{\"\x{c2}\x{c2}\"}") }; + #print $@; +} '<', 1; + +# wrong type croak +leaks_cmp_ok{ + use Cpanel::JSON::XS::Type; + my $js = Cpanel::JSON::XS->new->canonical->require_types; + eval { $js->encode([0], JSON_TYPE_FLOAT) }; + #print $@; +} '<', 1;