ivo Welch
ivo Welch

Reputation: 2866

perl storing hash in %ENV

I want to (ab-)use the global %ENV to store a hash. This seems to work differently for %ENV than for ordinary hashes. in the program below, the $ENV{myhash} still contains 'myhash' => 'HASH(0x7ffad8807380)' and the %ahash is still around. is it possible to convert the hex address back to point at its location, instead of just containing the string? I guess I could serialize and unserialize the hash instead. what is the right way to do this?

#!/usr/bin/perl -w

use common::sense;
use Data::Dumper;

my %QENV = ( nohash => 'noh' );
my %ahash= ( hv1 => 'htext1', hv2 => 'htext2' );
$QENV{'myhash'} = \%ahash;
print "works: ". Dumper(\%QENV)."\n\n\n";


$ENV{'myhash'} = \%ahash;
print "fails: ". Dumper(\%ENV)."\n";

Upvotes: 0

Views: 633

Answers (2)

stevieb
stevieb

Reputation: 9296

You seem to want to share data. Here's an example I put out there often that shows how to store data in a JSON file, then retrieve it. JSON is cross-language, so the data can be used by many programming languages, not just Perl. Although this example is within a single script, imagine it being two different Perl applications:

use warnings;
use strict;

use JSON;

my $file = 'data.json';

my %h = (
   foo => 'bar',
   raz => {
       ABC => 123,
       XYZ => [4, 5, 6],
   }
);

my $json = encode_json \%h;

# write the JSON to a file, and close it

open my $fh, '>', $file or die $!;
print $fh $json;
close $fh or die $!;

# open the JSON file, and read it

open my $json_file, '<', $file or die $!;

my $read_json;

{
    local $/;
    $read_json = <$json_file>;
}

my $perl_hash = decode_json $read_json;

Upvotes: 1

ikegami
ikegami

Reputation: 385915

%ENV is a magical hash. It reflects the process's environment. Reading from it reads from the environment, and writing to it changes the environment.

If you can guarantee the referenced variable is still alive (by it still being in scope or by it having its REFCNT increased), you can indeed create a reference to it from the address.

use strict;
use warnings;

use Data::Dumper;

use Inline C => <<'__EOS__';

   SV* _newRV(IV iv) {
      return newRV((SV*)iv);
   }

__EOS__

my %hash = ( a => 1, b => 2 );
my $ref = \%hash;
my $ref_string = "$ref";
my $addr = hex( ( $ref_string =~ /\((.*)\)/ )[0] );
my $ref2 = _newRV($addr);
print(Dumper($ref2));

I have no idea why you'd want to do this. It would not permit another process to access the data since one process can't access the memory of another.

Upvotes: 5

Related Questions