rurban / Cpanel-JSON-XS

Improved fork of JSON-XS

Home Page:http://search.cpan.org/dist/Cpanel-JSON-XS/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

boolean encoding is inconsistent

karenetheridge opened this issue · comments

perl -MCpanel::JSON::XS -wle'print Cpanel::JSON::XS->new->allow_nonref(1)->encode(!0)'
true
perl -MCpanel::JSON::XS -wle'print Cpanel::JSON::XS->new->allow_nonref(1)->encode([!0])'
[1]

This is with version 4.19.

13:37 < tinita> I think the problem is with !0 itself. as soon as you save it in an arrayref, its special status gets lost
13:38 < tinita> perl -wE'use Devel::Peek;Dump !0;Dump [!0]'
13:38 <@kraih> lol

so I guess this means it's not actually fixable. I hope I'm wrong though.

SV_yes and SV_no should not be interpreted as JSON booleans (unless via Cpanel::JSON::XS::Type with the boolean type). The user cannot easily tell if something they have is one of these special constants, they might accidentally encode one of them when trying to encode the number 1 (for example), and as demonstrated here they can de-special themselves. They are simply not reliably distinct from 0 and 1 in implementation or interface.

as demonstrated here they can de-special themselves

I don't agree with this part, as that's the same problem we have with the difference between the string "6" and the number 6, depending on how the value has been used be earlier code.

It is similar, and it's not good that that happens either. But in this case, we can avoid the problem and everything still works intuitively.

Not really, !0 is always SV_YES, even if as arrayref.

perl -Dx -e'print [!0]' =>  SV = SV_YES
perl -Dx -e'print !1' =>  SV = SV_NO

It's the anonlist in perl before the XS encode which changes the [yes] to [1].
With -Dts

(-e:1)	pushmark
    =>  **  \PVMG(""\0)  *  
(-e:1)	const(SV_YES)
    =>  **  \PVMG(""\0)  *  SV_YES  
(-e:1)	anonlist
    =>  **  \PVMG(""\0)  \AV()  
(-e:1)	method_named
    =>  **  \PVMG(""\0)  \AV()  CV(encode)  
(-e:1)	entersub
    =>  *  PV("[1]"\0) [UTF8 "[1]"]  

So it's av_make in anonlist which turns the SV_YES into 1, esp. sv_setsv_flags does not support the special immortals, like YES, NO, ... Upstream bug, sorry

BTW: Trivially fixable there, but it's already too late.

My concern is even if that were reliable, it's very common to already be using these values and expecting a 1 on encode, because it's generally indistinguishable from 1 in perl code. The boolean object is the only consistent and obvious way to represent something to be encoded to a boolean without Cpanel::JSON::XS::Type, and people are already used to it.