Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Tracking down uninitialized values...

by Slipstream (Monk)
on Jul 28, 2006 at 15:50 UTC ( [id://564376]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings Monks,

I'm maintaining code that was written years and years ago by someone other than myself. My job is to go through and clean it up a bit (better documentation, standardize the code, etc.)

Today I've run across a program that is creating massive log files filled with "Use of uninitialized value in join or string." I can think of a couple of (bad) ways of keeping that from getting logged, but in the interest of doing a good job and learning a little something on the way I'm trying to figure out how to pinpoint the cause and fix it correctly.

Does anyone have sound advice on what to read/research? Is this a job for the perl debugger? Anyone have any good experience related advice?

Thanks in advance my friends!

Replies are listed 'Best First'.
Re: Tracking down uninitialized values...
by philcrow (Priest) on Jul 28, 2006 at 15:56 UTC
    There is no easy way to really fix those warnings. But let me encourage you to do it anyway. Each one should have the offending module and line number already on it. Go there. It usually doesn't take much time to fix each one by either giving the variable a defined value or adding a test for definedness if undefs are proper values.

    Sorry I can't offer a quick fix for old messes.

    Phil

      You're right. On many that I've been fixing I was able to use the line number to fix it, however, this one has me stumped so I intentionally left out the additional info it gives in hopes of finding general answers for how to track them down vs. this specific instance. Though since I've mentioned it now, here's the full message: "Use of uninitialized value in join or string at (eval 39) line 15."

      Thanks for the quick response!

        You have to figure out what the 39th call to eval is, and look at line 15 in it:

        use warnings; foreach my $i ( 1..5, undef, 7..9 ) { eval '$x = join("",$i,"");'; } # Use of uninitialized value in join or string at (eval 6) line 1.
        If you don't have a good line number, start putting warn statements in the code. Their output will go to standard err just like the uninitialized value warnings, so they will appear in sequence with the problem. By knowing which warns come before and after the one you are tracking, you can locate it.

        Phil

        Update: corrected to show warn goes to stderr, thanks Hue-Bond.

Re: Tracking down uninitialized values...
by rodion (Chaplain) on Jul 28, 2006 at 16:30 UTC
    My experience is that once you get to the harder cases of uninitialized values, they are caused by variables where you stare at the it and think, "well that has to be there", and you later find out that it's not. The solution is to check each parameter at the entry to each function to see if it's defined, and kick off a warning or a die if it should be defined and isn't. It's tedious to write, and it interupts the flow when you're reading the code, but it saves lots of grief, IMO.

    It's also useful to have those checks in there when something changes with the data and the routine blows up, 6 months down the road.

      Both good suggestions (the above and the higher up about finding that certain eval). It seems like if the problem ends up being in a module that's being called it would be MUCH more difficult to track down by putting checks in the local code unless I played the elimination game of removing lines until the problem goes away.

      I thought I had read the debugger had a mode that would basically allow me to step through the program and see what happens as it executes. I was hoping I could use something like that to watch for exactly where/what it was complaining about.

      Time to visit the friendly manual some more. ;)
Re: Tracking down uninitialized values...
by imp (Priest) on Jul 28, 2006 at 18:32 UTC
    You could do this:
    use strict; use warnings; use Carp; # Configure the warn signal handler to print the stack trace provided +by Carp. $SIG{__WARN__} = sub {print STDERR Carp::longmess(@_); }; run(); sub run { my $code = eval 'sub { my $a = 1 - undef; };'; $code->(); }
    The output is:
    Use of uninitialized value in subtraction (-) at (eval 1) line 2. main::__ANON__() called at pm564376.pl line 14 main::run() called at pm564376.pl line 8
Re: Tracking down uninitialized values...
by kwaping (Priest) on Jul 28, 2006 at 17:15 UTC
    Many "mystery issues" of my own have been caused by typos in variable names. You might want to read the code very carefully and scan for that. Also, if you're using use warnings, you may see some "used only once" warnings for variables with typos in their names. Unfortunately, this doesn't hold true for normal hash keys.

    ---
    It's all fine and dandy until someone has to look at the code.
      Nice tip! Using that I was able to pinpoint from where the complaint was coming and fix it. It's not the elegant solution I was hoping for, but it worked and the problem's solved so how can I complain? ;)

      For those who are interested, here's the offending line of code causing 5MB of that warning:
      map{ td({align=>$align->{$_} || $default_align, valign=>$default_valig +n}, $main_row->{$_}) } @summary_columns;
      Only a couple of thousand more lines like that hidden around this massive system to deal with now. :P
Re: Tracking down uninitialized values...
by starbolin (Hermit) on Jul 28, 2006 at 17:32 UTC

    I have seen a lot of examples where the programmer created this problem by not checking return values. He does a call to a system function or a module function then uses the return value without testing for undef or false. These errors can propagate quite a ways through the code through various regexes and other manipulations. No, I don't know of any automated way of checking this. You need to check the documentation for each call for possible return values. Defensive programming is the word here. Every call returning a string or reference should be checked for both undef and null.


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://564376]
Approved by Hue-Bond
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-25 13:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found