Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

true/false data structure prevents changing values #25

Closed
zhengwy888 opened this issue Mar 12, 2015 · 12 comments
Closed

true/false data structure prevents changing values #25

zhengwy888 opened this issue Mar 12, 2015 · 12 comments

Comments

@zhengwy888
Copy link

When loading an yaml with true value, the value can't be modified as perl will complain 'changing a read-only value' . to reproduce

use YAML::XS qw(Load);
my $yaml = <<EOM;
hello: true
EOM
my $data = Load($yaml);
$data->{hello}= 1; #<-- this line will error out with 'Modification of a read-only value attempted ...'

I don't know if there is a reason why converting to a data structure that Perl can't modify.

@ratsbane
Copy link

ratsbane commented May 2, 2015

I'm not able to reproduce this problem or the output you're seeing. The syntax around your heredoc doesn't look right to me - I think it should be something like this instead:
my $yaml = <<EOM;
hello: true
EOM
my $data = Load($yaml);

@zhengwy888
Copy link
Author

@ratsbane sorry markdown ate my formatting. I have updated the comment with the correct format.
I was using perl 5.20.1 and YAML::XS 0.52.

@oalders
Copy link

oalders commented Jul 4, 2015

I can reproduce this under perl 5.18.2

@dolmen
Copy link

dolmen commented Sep 25, 2015

Here is a minimalist test case (verified on perl 5.20.1, YAML::XS 0.59):

$ perl -MYAML::XS -E 'Load("a: true")->{a} = !!0'
Modification of a read-only value attempted at -e line 1

This should not die.

@rurban
Copy link

rurban commented Oct 15, 2016

Looks like I have to implement the same trick as in JSON::XS, special overloaded symbols representing true and false.
A copy via newSVsv(&PL_sv_yes); helps with the readonly problem, but leads to lossage in the roundtrips:

test/boolean.t .......... 1/5
#   Failed test 'Booleans YNY roundtrip'
#   at test/boolean.t line 22.
#          got: '---
# a: 1
# b: 1
# c: ''
# d: ''
# '
#     expected: '---
# a: true
# b: 1
# c: false
# d: ''
# '

grazzini added a commit to grazzini/p5-YAML-LoadBundle that referenced this issue Nov 10, 2016
The import/flatten mechanism was processing every node in the
returned data structure, but:

1. That's not needed (the leaf nodes can never change)
2. YAML documents containing literal true/false values will
   contain read- only nodes, which means that we blow up trying
   to load them.

The glitch that causes GrantStreetGroup#2 is:

  ingydotnet/yaml-libyaml-pm#25

But the fix here will still be an improvement, even if that gets
corrected.
grazzini added a commit to grazzini/p5-YAML-LoadBundle that referenced this issue Nov 10, 2016
The import/flatten mechanism was processing every node in the
returned data structure, but:

1. That's not needed (the leaf nodes can never change)
2. YAML documents containing literal true/false values will
   contain read- only nodes, which means that we blow up trying
   to load them.

The glitch that causes GrantStreetGroup#2 is:

  ingydotnet/yaml-libyaml-pm#25

But the fix here will still be an improvement, even if that gets
corrected.
@mithun
Copy link

mithun commented Feb 28, 2017

The workaround is to delete the key and reset it

use YAML::XS qw(Load);
my $yaml = <<EOM;
hello: true
EOM
my $data = Load($yaml);
# This fails
# $data->{hello}= 1;
# This works
delete $data->{hello};
$data->{hello} = 1;

@zhengwy888
Copy link
Author

@rurban actually I think a round trip loss is not so much of an issue this case, since perl doesn't natively support true value so I don't think people expect that. plus we can have a flag to turn on/off this round trip value.
@mithun to avoid manually going into keys to find true/false I used JSON to dump than load the object to get rid of the true/false read only values.

@rurban
Copy link

rurban commented Feb 28, 2017

perl supports sv_yes and sv_no via the well-known constructs !!1 and !!0.

perl -MDevel::Peek -e'Dump !!1'
SV = PVNV(0x7fb312003610) at 0x10433ba00
  REFCNT = 2147483644
  FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x104300702 "1"
  CUR = 1
  LEN = 0

Note the overlarge refcount and PROTECT denoting an immortal protected special value, i.e. &PL_sv_yes.

@perlpunk
Copy link
Collaborator

Starting with YAML::XS 0.66_001, you can use this:

local $YAML::XS::Boolean = "JSON::PP"; # or "boolean"
my $data = Load("booltrue: true");
$data->{boolfalse} = JSON::PP::false;
my $yaml = Dump($data);
# boolfalse: false
# booltrue: true

See more about this in the docs. This also does not have the issue of readonly values.
I will close this issue, when 0.66_001 was tested by cpantesters and 0.67 was released.
Unless someone objects.
I was thinking about a third option "perl" that uses simple 1/'' instead of the special variables, but I'm not sure if this is really needed.

@SineSwiper
Copy link

I'd like to re-open this because this seems like the load_scalar code in perl_libyaml.c is doing this wrong: scalar = &PL_sv_yes;

Consider the following (using Perl 5.30):

$ perl -MDevel::Peek -e'Dump !!1'
SV = PVNV(0x558433cb0f80) at 0x558433caf3d8
  REFCNT = 2147483644
  FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x558431d9b864 "1"
  CUR = 1
  LEN = 0
$ perl -MDevel::Peek -e'my $t = !!1; Dump $t'
SV = PVNV(0x55e954ed6040) at 0x55e954f04938
  REFCNT = 1
  FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x55e954f27130 "1"\0
  CUR = 1
  LEN = 10

One is READONLY,PROTECT, and the other is not. I don't think the scalar can be set directly as a reference to the constant itself, like the code in perl_libyaml.c. It needs a newSV, and that constant stashed into the new SV.

@perlpunk
Copy link
Collaborator

perlpunk commented Sep 7, 2024

The current solution was chosen to be able to roundtrip booleans.
I've now created #118 which makes them not readonly for perl >= 5.36, where we got core boolean support.

@perlpunk
Copy link
Collaborator

#118 is now released as v0.902.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants