Perl: JSON fails if a thread is started - json

Can someone please tell my why JSON is not working if some thread is started?
use strict;
use warnings;
use JSON;
use threads;
use threads::shared;
sub th { }
threads->create(\&th)->join() if $ARGV[0];
my $json = to_json({ val => "123"}); # WTF?!?
print "$json\n";
Works fine and prints the JSON-string. But pass 1 as an argument to the script to create the thread and to_json will fail with
hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)
Same effect if I use encode_json insead.
On the manpage of JSON the word thread is not present and I see no reason why a thread should harm an outside string-conversion.
???

JSON(.pm) is just a front end for JSON::PP, JSON::XS or Cpanel::JSON::XS.
You have found a bug in JSON::XS. About this, JSON::XS's documentation says:
(I-)THREADS
This module is not guaranteed to be ithread (or MULTIPLICITY-) safe and there are no plans to change this. Note that perl's builtin so-called theeads/ithreads are officially deprecated and should not be used.
[Note that the last part is incorrect. The official position is actually: Threads are hard, so you should use something else instead. It's highly questionable since the alternatives are arguably just as hard.]
Workaround: Use one of the other backends (directly or via JSON(.pm)).
$ PERL_JSON_BACKEND=JSON::XS 46793885 0
{"val":"123"}
$ PERL_JSON_BACKEND=JSON::XS 46793885 1
hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this) at /home/ikegami/usr/perlbrew/perls/5.26.0t/lib/site_perl/5.26.0/JSON.pm line 170.
$ PERL_JSON_BACKEND=Cpanel::JSON::XS 46793885 1
{"val":"123"}
$ PERL_JSON_BACKEND=JSON::PP 46793885 1
{"val":"123"}
You can control this within the script by adding the following before loading JSON:
BEGIN { $ENV{PERL_JSON_BACKEND} = 'Cpanel::JSON::XS' }

I ran into this as well (trying to use JSON with multi-threaded perl). Without launching a background thread, my code worked fine, but got the same error you are getting when there was a thread launched.
Like you, I didn't find any help online specific to threading with regards to this error text. However, following the allow_nonref error text, I found the following in JSON::XS's documentation:
"OLD" VS. "NEW" JSON (RFC 4627 VS. RFC 7159)
TL;DR: Due to security concerns, JSON::XS will not allow scalar data in JSON >texts by default - you need to create your own JSON::XS object and enable
allow_nonref:
my $json = JSON::XS->new->allow_nonref;
$text = $json->encode ($data);
$data = $json->decode ($text);
In your case, you are trying to call to_json, which internally creates a JSON object and calls encode on it. Unfortunately it doesn't specify allow_nonref in its constructor. So to make your code work, you can do something like this:
use JSON::XS;
my $json_obj = JSON::XS->new->allow_nonref;
my $json = $json_obj->encode({ val => "123"});
print "$json\n";
I came up with this solution before reading the other responses here, so those may be better solutions, but this should at least get you past the issue with minimal changes.

This is definitely to do with JSON and global state.
If you require and import JSON, after the thread invocation, it 'works'.
The warning in the module for JSON::XS includes:
(I-)THREADS ^
This module is not guaranteed to be ithread (or MULTIPLICITY-) safe and there are no plans to change this
The 'workaround' for a not-thread-safe module is to not load it via use (which happens at 'compile' time) and instead require and import (at runtime) after the parallel instances of the program (threads) have been started.
E.g.:
use strict;
use warnings;
use threads;
use threads::shared;
sub th { }
my $th = threads->create( \&th )->join;
## Just inside main thread
##can do this within individual threads instead if desired
require JSON;
JSON->import;
my $json = to_json({ val => "123" }); # WTF?!?
print "\n$json\n";

Related

Extracting values from hash created by perl JSON::Syck::Load

I've got a very simple Perl issue that I can't for the life of me figure out.
I'm consuming JSON formatted data from a REST endpoint in a perl script. The data is shaped like this:
{
"ScriptRunning": true
}
There's some other stuff, but really all I care about is the ScriptRunning tag. I'm consuming this data using JSON::Syck::Load like so:
my $running_scripts = JSON::Syck::Load($output_from_rest_call)
(in my current environment it is not possible to get other libraries for CPAN, so I'm stuck with that). All that is working correctly as far as I can tell, I used Data::Dumper to confirm the data looks good:
$VAR1 = {
'ScriptRunning' => 1 # or '' if false
}
However, I can't figure out how to actually get the value of 'ScriptRunning'. I've done print ref $running_scripts and confirmed that it is a HASH, however when I try to index into the hash I'm not getting anything. I've tried the following:
my $script_is_running = $running_scripts{'ScriptRunning'};
my $script_is_running = $running_scripts{ScriptRunning};
my $keys_in_running_scripts = keys $running_scripts; # keys_in_running_scripts is empty
my $keys_in_running_scripts = keys %running_scripts; # keys_in_running_scripts is empty
Any ideas?
You need to use strict; (and use warnings; while you are at it, maybe use diagnostics; too, when you are really stuck). As a general rule, ALWAYS use strict; and use warnings; because they prevent problematic code from running and give you some much more helpful output.
You should also read perldoc perlreftut, which helps explain what you are dealing with.
Your variable $running_scripts is not a hash, but a "hash reference", which is an important distinction. When you call ref on a real hash, it returns a false value, since it is not a reference.
What you need to do is "dereference" using the arrow operator to get the value.
To get the keys call to work, there's a separate syntax for dereferencing.
my $script_is_running = $running_scripts->{ScriptRunning};
my #keys_in_running_scripts = keys %{$running_scripts};

Can't seem to do a Function.Invoke with multiple parameters in powershell?

I'm trying to pass a function to a method and then pass parameters to the method I passed when calling it, but if I pass more than one parameter then the method fails with an error:
function debugMeStuffs($someBlah, $somePoo) {
Write-Host $someBlah
Write-Host $somePoo
}
function invokeOnHosts ([scriptblock]$funcToCall, $param1, $param2, $startRange, $endRange) {
#Param($funcToCall)
$i = $startRange
for($i = [int]$startRange; $i -le $endRange; $i++) {
# HOW DO I MAKE THIS WORK WITH MULTIPLE PARAMETERS?!?!?!?
$funcToCall.Invoke('blah' 'poo')
}
}
invokeOnHosts $function:debugMeStuffs "param1" "param2" 4 7
Things I've tried:
$funcToCall("blah" "poo")
$funcToCall('blah' 'poo')
$funcToCall.Invoke("blah" "poo")
$funcToCall.Invoke('blah' 'poo')
$funcToCall 'blah' 'poo'
$funcToCall.Invoke 'blah' 'poo'
$funcToCall "blah" "poo"
$funcToCall.Invoke "blah" "poo"
None of the above seem to work. Is there something else I need to do to make this work?
.Invoke() is a .NET method, so the usual method-call syntax applies: you need
parentheses - (...) - around the list of arguments
you must separate the arguments with ,
$funcToCall.Invoke('blah', 'poo')
This contrasts with PowerShell's own syntax for calling cmdlets and functions, which is shell-like[1]:
no (...) around the argument list
arguments must be separated with spaces.
& $funcToCall blah poo # equivalent of the method call above.
A command such as the above is parsed in argument mode, which is why quoting the arguments in this simple case is optional.
Note the need for &, PowerShell's call operator, which is needed to execute the script block stored in $funcToCall; this is generally necessary for invoking a command stored in a variable, and also for command names / paths that are quoted.
Given that it's easy to get confused between PowerShell's command syntax and .NET's method syntax, it's best to stick with PowerShell-native features[2], if possible.
That said, being able to call methods on .NET types directly is a wonderful extensibility option.
To help avoid accidental use of method syntax when calling PowerShell commands, you can use Set-StrictMode -Version 2 or higher, but note that that entails additional strictness checks.
[1] PowerShell is, after all, a shell - but it is also a full-featured scripting language that offers near-unlimited access to the .NET framework.
Reconciling these two personalities is a difficult balancing act, and the shell-like command-invocation syntax is a frequent problem for newcomers with a programming background, given that the rest of the language looks like a traditional programming language and that calling methods on .NET types does use the traditional syntax.
[2] This means preferring PowerShell's cmdlets, functions, and operators to use of the underlying .NET types' methods; doing so also usually provides rewards you with operating at a higher level of abstraction.

Json in Perl error in opensips

What is the difference between json and json::PP in Perl?
I meet this error when use Json and Json:PP when writing perl script in opensips
ERROR:core:XS_OpenSIPS__Message_log:
perl warning: Prototype mismatch: sub main::decode_json ($) vs none.
I have problem with these codes:
my %postObject = ("callId" => $callID);
$postObject{'endTime'} = time() . "";
$postObject{'key'} = "12345#qwerty";
my $post_data = encode_json \%postObject;
The "Prototype mismatch" warning typically means that you've defined a sub twice in some way, and the two definitions' prototypes don't match.
Do you have a sub decode_json ($) in your main code somewhere? If you do, I'd suggest removing or renaming it, because it is conflicting with decode_json from one of the JSON modules. If you don't, then you may be getting a second decode_json from another module you are loading, in which case you'd have to track that down, or provide us with a Minimal, Complete, and Verifiable example.
I'd strongly recommend turning on warnings, because then you will additionally get "Subroutine redefined" warnings to help you track the issue down.

How does Ruby JSON.parse differ to OJ.load in terms of allocating memory/Object IDs

This is my first question and I have tried my best to find an answer - I have looked everywhere for an answer but haven't managed to find anything concrete to answer this in both the oj docs and ruby json docs and here.
Oj is a gem that serves to improve serialization/deserialization speeds and can be found at: https://github.com/ohler55/oj
I noticed this difference when I tried to dump and parse a hash with a NaN contained in it, twice, and compared the two, i.e.
# Create json Dump
dump = JSON.dump ({x: Float::NAN})
# Create first JSON load
json_load = JSON.parse(dump, allow_nan: true)
# Create second JSON load
json_load_2 = JSON.parse(dump, allow_nan: true)
# Create first OJ load
oj_load = Oj.load(dump, :mode => :compat)
# Create second OJload
oj_load_2 = Oj.load(dump, :mode => :compat)
json_load == json_load_2 # Returns true
oj_load == oj_load_2 # Returns false
I always thought NaN could not be compared to NaN so this confused me for a while until I realised that json_load and json_load_2 have the same object ID and oj_load and oj_load_2 do not.
Can anyone point me in the direction of where this memory allocation/object ID allocation occurs or how I can control that behaviour with OJ?
Thanks and sorry if this answer is floating somewhere on the internet where I could not find it.
Additional info:
I am running Ruby 1.9.3.
Here's the output from my tests re object IDs:
puts Float::NAN.object_id; puts JSON.parse(%q({"x":NaN}), allow_nan: true)["x"].object_id; puts JSON.parse(%q({"x":NaN}), allow_nan: true)["x"].object_id
70129392082680
70129387898880
70129387898880
puts Float::NAN.object_id; puts Oj.load(%q({"x":NaN}), allow_nan: true)["x"].object_id; puts Oj.load(%q({"x":NaN}), allow_nan: true)["x"].object_id
70255410134280
70255410063100
70255410062620
Perhaps I am doing something wrong?
I believe that is a deep implementation detail. Oj does this:
if (ni->nan) {
rnum = rb_float_new(0.0/0.0);
}
I can't find a Ruby equivalent for that, Float.new doesn't appear to exist, but it does create a new Float object every time (from an actual C's NaN it constructs on-site), hence different object_ids.
Whereas Ruby's JSON module uses (also in C) its own JSON::NaN Float object everywhere:
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
That explains why you get different NaNs' object_ids with Oj and same with Ruby's JSON.
No matter what object_ids the resulting hashes have, the problem is with NaNs. If they have the same object_ids, the enclosing hashes are considered equal. If not, they are not.
According to the docs, Hash#== uses Object#== for values that only outputs true if and only if the argument is the same object (same object_id). This contradicts NaN's property of not being equal to itself.
Spectacular. Inheritance gone haywire.
One could, probably, modify Oj's C code (and even make a pull request with it) to use a constant like Ruby's JSON module does. It's a subtle change, but it's in the spirit of being compat, I guess.

Why does XML::LibXML keeps printing errors even when I disable them?

I'm using XML::LibXML to parse a document.
The HTML file behind it, has some minor errors, and the parser reports them:
http://is.gd/create.php?longurl=http://google.com:15: validity error : ID smallink already defined
nal URL was http://google.com<span id="smallink"
^
http://is.gd/create.php?longurl=http://google.com:15: validity error : ID smallink already defined
and use http://is.gd/fNqtL-<span id="smallink"
^
However, I disabled error reporting:
my $parser = XML::LibXML->new();
$parser->set_options({ recover => 2,
validation => 0,
suppress_errors => 1,
suppress_warnings => 1,
pedantic_parser => 0,
load_ext_dtd => 0, });
my $doc = $parser->parse_html_file("http://is.gd/create.php?longurl=$url");
My only option to suppress those errors, is to run the script with 2>/dev/null, which I don't want. Could someone help me please get rid of those errors?
I have no idea if you're asking XML::LibXML corretly to not print its warnings. I'll assume you are and this is a bug in XML::LibXML (which you should also report to the author), and only address how to suppress warnings.
Every time a warning is about to be printed, perl will look up the value of $SIG{__WARN__} and, if that contains a code reference, invoke it instead of printing the warning itself.
You can use that stop the warnings you want to ignore to be printed to STDERR. However, you should be careful with this. Make sure to only suppress false-positives, not all warnings. Warnings are usually useful. Also, make sure to localize your use of $SIG{__WARN__} to the smallest possible scope to avoid odd side effects.
# warnings happen just as always
my $parser = ...;
$parser->set_options(...);
{ # in this scope we filter some warnings
local $SIG{__WARN__} = sub {
my ($warning) = #_;
print STDERR $warning if $warning !~ /validity error/;
};
$parser->parse_html_file(...);
}
# more code, now the warnings are back to normal again
Also note that this is all assuming those warnings come from perl-space. It's quite possible that libxml2, the C library XML::LibXML uses under the hood, writes warnings directly to stderr itself. $SIG{__WARN__} will not be able to prevent it from doing that.
A possible solution is to install a $SIG{__WARN__} handler which filters the messages or just silences all warnings:
local $SIG{__WARN__} = sub { /* $_[0] is the message */ };