mkaiser67 has asked for the wisdom of the Perl Monks concerning the following question:

I have an interesting issue with 'eval'.

I am using cgi Perl webpages looping throught parameters in a url, with an eval structure, to determine whether the parameter string is a json structure or not; if not then we have a need to encode the the parameter values:

{paraphrased code}

my @keys = %urlparams; foreach my $key (@keys) { eval { my $temp = from_json($urlparams{$key}); } or do { $input{$key} = HTML::Entities::encode($input{$key}); }; }

A URL like: https://mywebserver.edu/the.cgi?param_one=file.jpg|fileid|no_file&param_two=1|1|2|2 is expected to die on the json pyre and be encoded, which is fine, but it consistently leaks the JSON error message to STDERR on the last parameter, no matter the order of the parameters or number of them. That's not so cool.

we're using Perl 5.30, CGI::Carp,utf8,Text::Unidecode,HTML::Entities,JSON

Clearly i would like to know what's going on..
Any ideas? a memory leak of somekind?

Replies are listed 'Best First'.
Re: Perl evals and JSON
by choroba (Cardinal) on Mar 17, 2022 at 15:43 UTC
    What backend does JSON use? JSON::PP or JSON::XS, or even Cpanel::JSON::XS or JSON::backportPP? What version?

    Also, you probably want

    my @keys = keys %urlparams; # ~~~~

    Otherwise, you're processing values, too.

    Moreover, you probably want

    $input{$key} = HTML::Entities::encode($urlparams{$key}); # ~~~~~~~~~
    otherwise there's nothing to store.

    Can you share a snippet that actually reproduces your problem? I tried to fix you sample and ran it under JSON::PP, JSON::XS, and Cpanel::JSON::XS, but there were no errors.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Perl evals and JSON
by hippo (Archbishop) on Mar 17, 2022 at 15:47 UTC
    {paraphrased code}

    That's all very well but it makes it much harder for us to help you. Here's my SSCCE which does not reproduce your described problem.

    use strict; use warnings; use Test::More tests => 1; use Test::NoWarnings; use JSON; my $text = 'file.jpg|fileid|no_file&param_two=1|1|2|2'; eval { my $temp = from_json ($text); } or do { print "# Not JSON\n"; };

    🦛

Re: Perl evals and JSON (CGI::Carp / updated)
by LanX (Saint) on Mar 17, 2022 at 15:40 UTC
    do you have a %SIG handler activated, like with CGI::Carp ?

    Update

    Oops, I just noticed you mentioned CGI::Carp explicitly, so my guess was not far fetched. And it's using SIG-handlers to intercept those errors.

    Problem is, that SIG handlers need to to take care about being called inside an eval. They need to check $^S and ignore those exceptions.

    The $SIG{__DIE__} hook is called even inside an eval(). It was never intended to happen this way, but an implementation glitch made this possible. This used to be deprecated, as it allowed strange action at a distance like rewriting a pending exception in $@. Plans to rectify this have been scrapped, as users found that rewriting a pending exception is actually a useful feature, and not a bug.

    Update

    Well the solution is explicitely documented in

    CGI::Carp#SUPPRESSING-PERL-ERRORS-APPEARING-IN-THE-BROWSER-WINDOW

    A problem sometimes encountered when using fatalsToBrowser is when a die() is done inside an eval body or expression. Even though the fatalsToBrower support takes precautions to avoid this, you still may get the error message printed to STDOUT. This may have some undesirable effects when the purpose of doing the eval is to determine which of several algorithms is to be used.

    By setting $CGI::Carp::TO_BROWSER to 0 you can suppress printing the die messages but without all of the complexity of using set_die_handler. You can localize this effect to inside eval bodies if this is desirable: For example:

    eval { local $CGI::Carp::TO_BROWSER = 0; die "Fatal error messages not sent browser" } # $@ will contain error message

    Please check, if this solves your problem!

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: Perl evals and JSON
by cavac (Prior) on Mar 21, 2022 at 15:50 UTC

    with an eval structure, to determine whether the parameter string is a json structure or not

    Sounds a bit sketchy, to say the least. Technically, how do you distinguish, for example, between a JSON structure and a comment that posts an example JSON structure.

    I mean yes, you could do the automatic thing you're doing, but in my opinion you should have some design definitions that clearly state which parameters are expected to be JSON and which parameters are expected NOT to contain JSON. For example, is

    {}

    just a text or a very minimal JSON parameter? Without context, it really could be either. This can, under certain circumstances, create quite the security problem.

    perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'