Front page | perl.perl5.porters |
Postings from October 2009
[perl #70067] Variable Suicide Involving Dispatch Tables
Thread Previous
|
Thread Next
From:
David Yingling
Date:
October 28, 2009 02:44
Subject:
[perl #70067] Variable Suicide Involving Dispatch Tables
Message ID:
rt-3.6.HEAD-5412-1256701677-87.70067-75-0@perl.org
# New Ticket Created by David Yingling
# Please include the string: [perl #70067]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=70067 >
Subject: Variable Suicide Involving Dispatch Tables
Message-Id: <5.10.1_30862_1256685977@betty>
Reply-To: deeelwy@yahoo.com
To: perlbug@perl.org
This is a bug report for perl from deeelwy@yahoo.com,
generated with the help of perlbug 1.39 running under perl 5.10.1.
-----------------------------------------------------------------
[Please describe your issue here]
After checking the perlfaqs to see if what I was experiencing was really a bug or not, I came across perlfaq7, and the question about "variable suicide." This question paralleled the problem I'm having. Only instead of the cause of the problem being with closures and foreach loop variables, it is with defining a dispatch table in one subroutine (A), then executing another subroutine (B) passing a reference to that dispatch table, and then having that subroutine execute the different elements of the dispatch table based on parsing and conditions. Subroutine B also passes some variables to the subroutines in the dispatch table, 2 by copy and 1 by reference.
The included code is basically just a stripped down version of the program that I'm writing. The test code provided (but not in perl test format) implements what I call "macro substitution," which just replaces macros (variables) in a configuration file with their values.
This program parses a configuration file, which is represented by the faked @lines array. This array has a general purpose parser called parse_config(). parse_config() takes a dispatch table (hash of coderefs) and the array to parse as arguments. It compares the lines of array to a bunch of conditionals and then executes whichever callback subroutine is related to that condition and it passes 3 arguments to this callback.
This callback was defined inside the macrofy_config() subroutine. macrofy_config() just prints some debugging output, and executes parse_config() twice to do the parsing, because the algorithm it uses actually needs to do this twice--Once to parse out the macros to build the %macros hash, and another time to replace the macros with their values.
The problem is that some of the variables I have declared "disappear" they lose their definition and their value. These variables are %macros, $fake_hash, and @macros. $fake_hash and @macros are my poor attempts at a workaround using different data types. My thinking was the problem was with hashes and not all kinds of variables; however, none of those workarounds worked. I left them in the example test code below in case you would want to test them.
Below are 2 programs. The first one (perlbug.pl) includes the code that causes the "variable suicide" as demonstrated by its output and the warnings about using undefined variables, which if you look at the code have both been defined and are still in scope. The second one (perlworkaround.pl) includes a workaround that fixes the problem and demonstrates what the output "should" look like
Either copy and paste the output into files, or download the attachments. I'd also like to mention that this code is not polished, and still in development.
[START perlbug.pl]
#!/usr/bin/env perl
# use the latest version 5.10.1.
use warnings;
use diagnostics;
use strict;
# Enable Perl 6 knock offs.
use feature ':5.10';
use Data::Dumper;
my $config_file = './fakeconfigfile.conf';
#Fake configuration file
my @lines = (
'$prefix = --prefix=/usr/local',
'$conf_opts = --enable-assembler',
'ConfigureOptions $conf_opts $prefix');
#Prepend the name of the configuration file to the array. This is so that line
#numbers will line up with array indexes.
unshift @lines, "$config_file";
my %macros;
my @macros;
my $fake_hash;
#macrofy_config() to replace macros with their values.
macrofy_config(\@lines);
# macrofy_config() does the macro substitution to put the values of macros
# where those macros are used.
sub macrofy_config {
my $lines = shift;
my $macro_declaration_config = {
'MACRO_DECLARATION' => sub {
my ($z, $line, $curr_hier) = @_;
say "Macro definition [$$line]";
# Turn macro definitions ($macro\s=\s'macro definition') into
# %macros for processing by the next sub.
#split on '=' to get the variable name and everything after it.
#Use split's 3rd argument to just get variable declaration and then
#"everything else", so you can't declare multiple variables on one
#line. Includes whitespace on either side to strip it out of the
#returned values.
my ($macro, $macro_value) = split /\s*=\s*/, $$line, 2;
#clean up $macro and $macro_value.
chomp $macro; chomp $macro_value;
$macro =~ s/\s+$//; $macro_value =~ s/\s+$//;
$macro =~ s/^\s+//; $macro_value =~s/^\s+//;
$macro_value =~ s/^\s*['"]//; $macro_value =~ s/['"]\s*$//;
#delete macro char $ that might conflict with per's sigils.
$macro =~ s/\$//;
say "Macro:\[$macro\]";
say "Macro Value:\[$macro_value\]";
#Autovivicate the hash for the textual substitution.
$macros{$macro} = $macro_value;
#push @macros, [$macro, $macro_value];
#Try a stringified hash as a workaround for the potential, maybe
#perl bug I found.
#pack_fake_hash($fake_hash, $macro);
#pack_fake_hash($fake_hash, $macro_value);
say "autovivicated [$macro_value] into macros at [$macro].";
#Delete this line from the @$lines array to avoid confusing
#read_config(), with macro definitions it knows nothing about.
#Delete line by assigning it undef, which makes parse_config()
#ignore it.
say "Deleting line [$$line] from \@\$lines array!";
$$line = undef;
},
};
my $macro_substitution_config = {
'MACRO_SUBSTITUTION' => sub {
my ($z, $line, $curr_hier) = @_;
say "Macro substitution [$$line]";
LINE: {
#Regex capture out the $macro name from the line, and so I can check its length().
$$line =~ /(\$\w+\b)/; #Macros are letters, numbers and _'s like perl identifiers.
my $macro = $1;
print "Macro \[$macro\]\n";
#append a $ symbol back on.
say "macro with symbol [$macro]";
my $length = 0;
$length = length $macro;
print "Length $length\n";
print "Macro \[$macro\]\n";
my $index = 0;
$index = index $$line, $macro;
print "Index [$index]\n";
#poptential workaround
#my %macros = unpack_fake_hash($fake_hash);
#say "macro value [$macros{$macro}]";
#say "macro value [@{[fake_hash_value(\@macros, $macro)]}]";
say "macro value [$macros{$macro}]";
#Use substr to remove $macro and replace it with the macro's value, $macros{$macro}.
substr ($$line, $index, $length) = $macros{$macro};
print "REPLACED macro [$macro] with macro value [$macros{$macro}]: [$$line]\n";
#If after processing the first $ char (e.g. macro), there is another $ char (e.g. macro), then
#redo the loop again, and if there's another, redo it again, and so on recursively to
#textually substitute all macros into their value for this line.
if ($$line =~ /\$/) {
print q(STARTING RECURSION: There are 2 or more $'s in this string),
"\n";
redo LINE;
}
}
},
};
say 'Before macroy_config() => MACRO_DECLARATION', "\n", pretty_lines();
parse_config($lines, $macro_declaration_config);
say 'After macrofy_config() => MACRO_DECLARATION', "\n", pretty_lines();
say "Printing Macros";
say "Macro:[$_] :: Macro Value:[$macros{$_}]" for (keys %macros);
#say "Macro:[$_->[0] :: Macro Value:[$_->[1]]" for (@macros);
#my %temphash = unpack_fake_hash($fake_hash);
#say "Macro:[$_] :: Macro Value:[$temphash{$_}]" for (keys %temphash);
say 'Before macrofy_config() => MACRO_SUBSTITUTION', "\n", pretty_lines();
parse_config($lines, $macro_substitution_config);
say 'After macrofy_config() => MACRO_SUBSTITUTION', "\n", pretty_lines();
}
#parse_config() accepts a ref to an array of lines to operate on, and a ref to a
#hash of subs, whose keys matchup with special constants, and whose values are
#subs containing what actions should be performed for each type of event.
#
#Below is an example of what $actions is supposed to look like. Do not call
#parse_config() with emptly sub {}'s if you do it will call those empty subs for
#those handlers; therefore, only put what events you actually need to use into
#the %actions you use to call parse_config().
#my %actions = (
# 'MACRO_DECLARATION' => sub {},
# 'MACRO_SUBSTITUTION' => sub {},
# 'DEFAULT' => sub {}
#);
#
#Each anonymous subroutine in $actions is passed 3 arguments the current line
#number, then the value of the current line as scalars, and then $curr_hier[-1],
#which the tag handlers need access to like so:
#$actions->{WHICHONE}($z, \$lines->[$z], $curr_hier[-1]);
#The current line ($lines->[$z]) is passed to each handler as a reference, so
#that the handler can modify that reference, which modifies the current line.
#Used to delete lines by setting it to undef, or to substr out comments.
sub parse_config {
my $lines = shift;
my $actions = shift;
#define a context variable that tracks what hierarchy the loop is currently in
#is 'Global' for Global or $1 from /<(.*)\s..../ for tags--the first word in
#a tag, and @curr_hier[1,2].
my @curr_hier = ['Global'];
#Iterate over $lines except the first one, because the first one is the
#filename, and is used so that the first "real" line number in the config
#file starts at index 1 to make keeping track of what line number I'm on for
#error reporting much easier than parrallel arrays or an array of arrays.
LINE: for (my $z = 1; $z <= $#$lines; $z++) {
say "Line # [$z] <==> Line [$lines->[$z]]";
given($lines->[$z]) {
#Has this line been deleted?
when (/=/ and /\$/ #Must match $ too or it'll catch macro substitutions too.
and #And we're not inside a Code section!
$curr_hier[-1][0] ne 'Code') {
#macro declaration handler
$actions->{MACRO_DECLARATION}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{MACRO_DECLARATION};
#Is this line a macro substitution?
} when (/\$/
and #And we're not inside a Code section!
$curr_hier[-1][0] ne 'Code') {
#macro substitution handler
$actions->{MACRO_SUBSTITUTION}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{MACRO_SUBSTITUTION};
} default {
#Whoops! It should be impossible to get here as all of the
#possibilities should have been covered above.
#Have a default handler for this one, but allow it to be overwritten
#too, because check_config($z, \$lines->[$z], $curr_hier[-1]) will probably want to overwrite this
#one.
$actions->{DEFAULT}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{DEFAULT};
}
}
}
}
#pretty_lines() returns a list of @lines or whatever array ref is passed to it,
#but prettized.
sub pretty_lines {
my $lines = shift;
my @return;
unless (defined($lines)) {
for my $l (0..$#lines) {
if ($l == 0) {
push @return, "Printing configuration file: $lines[$l]\n";
} elsif ($lines[$l] eq undef) {
push @return, "$l:\t[[__UNDEF__]]\n";
} else {
push @return, "$l:\t$lines[$l]\n";
}
}
return @return;
} else {
#Loops through the array ref you pass in.
for my $l (0..$#$lines) {
if ($l == 0) {
push @return, "Printing configuration file: $lines->[$l]\n";
} elsif ($lines->[$l] eq undef) {
push @return, "$l:\t[[__UNDEF__]]\n";
} else {
push @return, "$l:\t$lines->[$l]\n";
}
}
return @return;
}
}
sub fake_hash_value {
my $array = shift;
my $key = shift;
for (@$array) {
next unless $_[0] eq $key;
return $_[1];
}
}
{ #Stupid fake block for scope reasons to share these 2 vars with 2 subs instead
# of just one.
state @fake_hash;
state $template = 'A';
sub pack_fake_hash {
my $string = shift;
push @fake_hash, $string;
#pack and return the fake hash as a scalar.
pack $template, @fake_hash;
}
sub unpack_fake_hash {
my $fake_hash = shift;
#return the list of packed values to probably put into a hash.
unpack $template, $fake_hash;
}
}#end of stupid fake block for scoping reasons.
[END perlbug.pl]
[START perlworkaround.pl]
#!/usr/bin/env perl
# use the latest version 5.10.1.
use warnings;
use diagnostics;
use strict;
# Enable Perl 6 knock offs.
use feature ':5.10';
use Data::Dumper;
my $config_file = './fakeconfigfile.conf';
#Fake configuration file
my @lines = (
'$prefix = --prefix=/usr/local',
'$conf_opts = --enable-assembler',
'ConfigureOptions $conf_opts $prefix');
unshift @lines, "$config_file";
my %macros;
# macrofy_config() does the macro substitution to put the values of macros
# where those macros are used.
sub macrofy_config {
my $lines = shift;
say 'Before macroy_config() => MACRO_DECLARATION', "\n", pretty_lines();
parse_config($lines, {'MACRO_DECLARATION' => \¯o_substitute});
say 'After macrofy_config() => MACRO_DECLARATION', "\n", pretty_lines();
say "Printing Macros";
say "Macro:[$_] :: Macro Value:[$macros{$_}]" for (keys %macros);
say 'Before macrofy_config() => MACRO_SUBSTITUTION', "\n", pretty_lines();
parse_config($lines, {'MACRO_SUBSTITUTION' => \¯o_substitute});
say 'After macrofy_config() => MACRO_SUBSTITUTION', "\n", pretty_lines();
}
# macro_substitute() does the actual work of the macro substitution, and is a
# parse_config() parser used by macrofy_config() to hopefully avoid a weird
# "variable suicide" bug in Perl I think I found.
sub macro_substitute {
my ($z, $line, $curr_hier) = @_;
#Process Macro declarations
if ($$line =~ /=/ and $$line =~ /\$/) {
say "Macro definition [$$line]";
# Turn macro definitions ($macro\s=\s'macro definition') into %macros for processing by the next loop.
#split on '=' to get the variable name and everything after it.
#Use split's 3rd argument to just get variable declaration and then "everything else", so you can't declare
#multiple variables on one line.
#Includes whitespace on either side to strip it out of the returned values.
my ($macro, $macro_value) = split /\s*=\s*/, $$line, 2;
#Chomp the newline if any off of the macro key and value.
chomp $macro; chomp $macro_value;
#Strip trailing whitespace off of the $macro key and value.
$macro =~ s/\s+$//; $macro_value =~ s/\s+$//;
#Strip leading whitespace off of the $macro key and value.
$macro =~ s/^\s+//; $macro_value =~s/^\s+//;
#Strip any quotes off of the $macro_value.
$macro_value =~ s/^\s*['"]//; $macro_value =~ s/['"]\s*$//;
say "Macro:\[$macro\]";
say "Macro Value:\[$macro_value\]";
#Autovivicate the hash that the next loop uses for the textual substitution.
$macros{$macro} = $macro_value;
say "autovivicated [$macro_value] into macros at [$macro].";
#Delete this line from the @$lines array to avoid confusing
#read_config(), with macro definitions it knows nothing about.
#Delete line by assigning it undef, which makes parse_config()
#ignore it.
say "Deleting line [$$line] from \@\$lines array!";
$$line = undef;
#Do macro substitutions.
} elsif ($$line =~ /\$/) {
say "Macro substitution [$$line]";
LINE: {
#Regex capture out the $macro name from the line, and so I can check its length().
$$line =~ /(\$\w+\b)/; #Macros are letters, numbers and _'s like perl identifiers.
my $macro = $1;
print "Macro \[$macro\]\n";
my $length = 0;
$length = length $macro;
print "Length $length\n";
print "Macro \[$macro\]\n";
my $index = 0;
$index = index $$line, $macro;
print "Index [$index]\n";
say "macro value [$macros{$macro}]";
#Use substr to remove $macro and replace it with the macro's value, $macros{$macro}.
substr ($$line, $index, $length) = $macros{$macro};
print "REPLACED macro [$macro] with macro value [$macros{$macro}]: [$$line]\n";
#If after processing the first $ char (e.g. macro), there is another $ char (e.g. macro), then
#redo the loop again, and if there's another, redo it again, and so on recursively to
#textually substitute all macros into their value for this line.
if ($$line =~ /\$/) {
print q(STARTING RECURSION: There are 2 or more $'s in this string),
"\n";
redo LINE;
}
}
}
}
#macrofy_config() to replace macros with their values.
macrofy_config(\@lines);
#parse_config() accepts a ref to an array of lines to operate on, and a ref to a
#hash of subs, whose keys matchup with special constants, and whose values are
#subs containing what actions should be performed for each type of event.
#
#Below is an example of what $actions is supposed to look like. Do not call
#parse_config() with emptly sub {}'s if you do it will call those empty subs for
#those handlers; therefore, only put what events you actually need to use into
#the %actions you use to call parse_config().
#my %actions = (
# 'MACRO_DECLARATION' => sub {},
# 'MACRO_SUBSTITUTION' => sub {},
# 'DEFAULT' => sub {}
#);
#
#Each anonymous subroutine in $actions is passed 3 arguments the current line
#number, then the value of the current line as scalars, and then $curr_hier[-1],
#which the tag handlers need access to like so:
#$actions->{WHICHONE}($z, \$lines->[$z], $curr_hier[-1]);
#The current line ($lines->[$z]) is passed to each handler as a reference, so
#that the handler can modify that reference, which modifies the current line.
#Used to delete lines by setting it to undef, or to substr out comments.
sub parse_config {
my $lines = shift;
my $actions = shift;
#define a context variable that tracks what hierarchy the loop is currently in
#is 'Global' for Global or $1 from /<(.*)\s..../ for tags--the first word in
#a tag, and @curr_hier[1,2].
my @curr_hier = ['Global'];
#Iterate over $lines except the first one, because the first one is the
#filename, and is used so that the first "real" line number in the config
#file starts at index 1 to make keeping track of what line number I'm on for
#error reporting much easier than parrallel arrays or an array of arrays.
LINE: for (my $z = 1; $z <= $#$lines; $z++) {
say "Line # [$z] <==> Line [$lines->[$z]]";
given($lines->[$z]) {
#Has this line been deleted?
when (/=/ and /\$/ #Must match $ too or it'll catch macro substitutions too.
and #And we're not inside a Code section!
$curr_hier[-1][0] ne 'Code') {
#macro declaration handler
$actions->{MACRO_DECLARATION}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{MACRO_DECLARATION};
#Is this line a macro substitution?
} when (/\$/
and #And we're not inside a Code section!
$curr_hier[-1][0] ne 'Code') {
#macro substitution handler
$actions->{MACRO_SUBSTITUTION}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{MACRO_SUBSTITUTION};
} default {
#Whoops! It should be impossible to get here as all of the
#possibilities should have been covered above.
#Have a default handler for this one, but allow it to be overwritten
#too, because check_config($z, \$lines->[$z], $curr_hier[-1]) will probably want to overwrite this
#one.
$actions->{DEFAULT}($z, \$lines->[$z], $curr_hier[-1]) if defined $actions->{DEFAULT};
}
}
}
}
#pretty_print() returns a list of @lines or whatever array ref is passed to it,
#but prettized.
sub pretty_lines {
my $lines = shift;
my @return;
unless (defined($lines)) {
for my $l (0..$#lines) {
if ($l == 0) {
push @return, "Printing configuration file: $lines[$l]\n";
} elsif ($lines[$l] eq undef) {
push @return, "$l:\t[[__UNDEF__]]\n";
} else {
push @return, "$l:\t$lines[$l]\n";
}
}
return @return;
} else {
#Loops through the array ref you pass in.
for my $l (0..$#$lines) {
if ($l == 0) {
push @return, "Printing configuration file: $lines->[$l]\n";
} elsif ($lines->[$l] eq undef) {
push @return, "$l:\t[[__UNDEF__]]\n";
} else {
push @return, "$l:\t$lines->[$l]\n";
}
}
return @return;
}
}
[END perlworkaround.pl]
Below is the important output from perlbug.pl.
Use of uninitialized value within %macros in concatenation (.) or string at
./perlbug.pl line 103 (#1)
macro value []
Use of uninitialized value in concatenation (.) or string at ./perlbug.pl line
107 (#1)
REPLACED macro [$conf_opts] with macro value []: [ConfigureOptions $prefix]
STARTING RECURSION: There are 2 or more $'s in this string
Macro [$prefix]
macro with symbol [$prefix]
Length 7
Macro [$prefix]
Index [18]
macro value []
REPLACED macro [$prefix] with macro value []: [ConfigureOptions ]
After macrofy_config() => MACRO_SUBSTITUTION
Printing configuration file: ./fakeconfigfile.conf
1: [[__UNDEF__]]
2: [[__UNDEF__]]
3: ConfigureOptions
The problem is that on line 103 %macros is still in scope and "should" be accessible, but it isn't. It is already defined, because it is printed out in earlier output.
Below is output from perlworkaround.pl
Line # [3] <==> Line [ConfigureOptions $conf_opts $prefix]
Macro substitution [ConfigureOptions $conf_opts $prefix]
Macro [$conf_opts]
Length 10
Macro [$conf_opts]
Index [17]
macro value [--enable-assembler]
REPLACED macro [$conf_opts] with macro value [--enable-assembler]: [ConfigureOptions --enable-assembler $prefix]
STARTING RECURSION: There are 2 or more $'s in this string
Macro [$prefix]
Length 7
Macro [$prefix]
Index [36]
macro value [--prefix=/usr/local]
REPLACED macro [$prefix] with macro value [--prefix=/usr/local]: [ConfigureOptions --enable-assembler --prefix=/usr/local]
After macrofy_config() => MACRO_SUBSTITUTION
Printing configuration file: ./fakeconfigfile.conf
1: [[__UNDEF__]]
2: [[__UNDEF__]]
3: ConfigureOptions --enable-assembler --prefix=/usr/local
This is the correct output, and perlbug.pl should also produce this if it weren't for the bug. The major difference is that the actual macro substitution completed successfully as in the "--enable-assembler" and "--prefix=/usr/local" parts are there. Compare this to the perlbug.pl output repasted below.
3: ConfigureOptions
Notice that "--enable-assembler" and "--prefix=/usr/local" are NOT in this output. These are the values of the %macros hash, and these are the values that "disappear" when %macros commits "variable suicide"
Thank you for checking into my bug report, and for helping to develop and
maintain perl,
Dave.
[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags:
category=core
severity=high
---
Site configuration information for perl 5.10.1:
Configured by dly at Mon Oct 5 00:51:30 EDT 2009.
Summary of my perl5 (revision 5 version 10 subversion 1) configuration:
Platform:
osname=linux, osvers=2.6.29.6-aacraid, archname=x86_64-linux
uname='linux betty 2.6.29.6-aacraid #2 smp mon sep 28 01:40:26 edt 2009 x86_64 intel(r) core(tm)2 duo cpu e8400 @ 3.00ghz genuineintel gnulinux '
config_args='-de'
hint=recommended, useposix=true, d_sigaction=define
useithreads=undef, usemultiplicity=undef
useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
use64bitint=define, use64bitall=define, uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2',
cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
ccversion='', gccversion='4.3.3', gccosandvers=''
intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries:
ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64 /usr/local/lib64
libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc
perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
libc=/lib/libc-2.9.so, so=so, useshrplib=false, libperl=libperl.a
gnulibc_version='2.9'
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'
Locally applied patches:
---
@INC for perl 5.10.1:
/usr/local/lib/perl5/5.10.1/x86_64-linux
/usr/local/lib/perl5/5.10.1
/usr/local/lib/perl5/site_perl/5.10.1/x86_64-linux
/usr/local/lib/perl5/site_perl/5.10.1
.
---
Environment for perl 5.10.1:
HOME=/home/dly
LANG=en_US
LANGUAGE=
LC_COLLATE=C
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib64/java/bin:/usr/lib64/kde4/libexec:/usr/lib64/qt/bin:.:/home/dly/bin
PERL_BADLANG (unset)
SHELL=/bin/bash
Thread Previous
|
Thread Next