Subject: | Nested Code References Crash |
Date: | Mon, 19 Aug 2019 17:05:58 +0100 |
To: | "Const::Fast RT" <bug-Const-Fast [...] rt.cpan.org> |
From: | Smylers <smylers [...] stripey.com> |
Hi. Const::Fast crashes with this error message if the constant's value is a nested data structure which contains a code-ref deeper than the first level:
Can't store CODE items at .../Const/Fast.pm line 29.
So an array containing code-refs is fine:
const my @CodeList => (sub { }, sub { });
As is a hash with a code-ref in a value:
const my %Record => (code => sub { });
But putting those two together fails, with the above error message:
const my @RecordList => ({code => sub { }}, {code => sub { }});
That's caused by _make_readonly's call to _dclone. Since version 0.0.14, that's skipped if $reftype is 'CODE', but that doesn't do any good for a hash or array which includes code within it.
Telling Storable to use eval makes it work
$Storable::Eval = $Storable::Deparse = 1;
const my @RecordList => ({code => sub { }}, {code => sub { }});
$Storable::Eval = $Storable::Deparse = 0;
But having to do that seems suboptimal.
Why is the ‘more than 1 ref-count’ check triggering here anyway? There isn't an external reference to anything in this data structure (which is what I'm guessing the deep copy is supposed to avoid), so a ref-count of 2 appears to be ‘safe’ here.
Is the second ref-count a bi-product of _make_readonly's traversing the data structure? If so, could the threshold in the ref-count safely be made 2 rather than 1 when _make_readonly is recursing?
Thanks.
Smylers