http://www.perlmonks.org?node_id=1020531

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

Hello Monks,

It seems I got some kind of Heisenbug. In my code, there seems to be something wrong, but I can not track it down by debuging. I got a working peace of code. Now, as I want to extend the functionality it seems that variables turning to be defined / undefined depending if going into and return from a subfunction.

It looks like this:

package DATABASE_ANALYSIS; use strict; use warnings; use diagnostics; use DBI qw(:sql_types); use DBD::SQLite; use ITF::ErrorHandling; use vars qw($VERSION $HEADER @ISA @EXPORT); use Exporter; $VERSION = q$Revision: 0.0.1 $; $HEADER = q$Header: DATABASE_ANALYSIS$; @ISA = qw(Exporter); @EXPORT = qw( ConnectToDatabase($) GetDBContent Disconnect GetParent ResolveContainer ); my ( $comp_by_pac, $container_by_pac, $containers, $src_by_comp, $src_by_test, $xml_structure, $analyzed_comps, $root_dir, $project_root, $PAC_by_Id, $COMP_by_Id, $TEST_by_Id, $COMPs_by_Name, $REL_by_Parent, $REL_by_Child, $dbh ); sub ProcessContainers { my $start_container = $_[0]; my $container; #Process PAC or COMP if given. if ( not defined $start_container ) { $start_container = $PAC_by_Id->{1}{'Name'}; } #If no token is given on command line, then the project name is #taken as standard token - script dies in case it does not exist die "Could not find Project name, try to provide project name (PAC) as tok +en! --token=MyProjectName " if ( not defined $start_container ); #Resolve all subsequent appearing PAC and STCOMP to COMPS #Background: COMPS can directly resolved to SourceFiles # 1. Get starting contianer # 2. Resolve subsequent containers if ( exists $container_by_pac->{$start_container} ) { $container = ${ $container_by_pac->{$start_container} }; } elsif ( exists $containers->{$start_container} ) { $container = $containers->{$start_container}; } #Add to xml structure $xml_structure->{$start_container} = $container; ResolveContainers($container); } sub ResolveContainers { my $start_container = $_[0]; goto COMPPROCESSING if ( ref $start_container eq 'HASH' ); foreach my $item ( @{$start_container} ) { if ( ( $item->[1] eq 'PAC' ) or ( $item->[1] eq 'STCOMP' ) ) { #Recursive analysis ResolveContainers( ${ $container_by_pac->{ $item->[0] } } +); } else { #Add Element to comps list $analyzed_comps->{ $item->[0] } = $item; } } return; COMPPROCESSING: #Add Element to comps list $analyzed_comps->{ $start_container->{'Name'} } = $start_container +; return; }
Notice the global variables in the package. They are defined by calling other functions not put into this code collection here.

However, I am calling the ProcessContianer sub with appropriate parameter. Most important here, it is initializing the $xml_structure variable at the end. I can verify the values in the Eclipse-Debugger (EPIC plugin) and all looks fine!. Then I am calling the ResolveContainers sub. Once I am inside this function all globals (to this package) turning to undef but one $container_by_pac. Even the variable I was passing to the subfunction is listed as undef. Doing a print in the debugger is also giving me nothing -> undef.

However, once in the called ResolveContainer sub I assign the parameter which is listed as undef to the $start_container variable. It works perfect. There are all expected values. How comes it that way?

Any help is appreciated!

Best regards! Tobias

  • Comment on package variables turning suddenly to undef and back again depending on subfunction call
  • Select or Download Code

Replies are listed 'Best First'.
Re: package variables turning suddenly to undef and back again depending on subfunction call
by Athanasius (Archbishop) on Feb 25, 2013 at 16:33 UTC
    Doing a print in the debugger is also giving me nothing -> undef.

    Before anything else: Turn off the debugger, and put (ordinary Perl) print statements, showing the values of the package globals,

    • immediately before the call to ResolveContainers
    • on entry to ResolveContainers
    • immediately before the 2 return statements in ResolveContainers
    • immediately following the return of sub ResolveContainers within sub ProcessContainers.

    If the variables still go from defined to undef and back, there is a bug in the Perl script. But if the variables keep their correct values, there is simply a bug in the Eclipse-Debugger.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      I have tested it with print statements, it seems its a problem with the eclipse-plugin or the debugger because values are not undef. :-)

      Thanks a lot!
      Tobias

Re: package variables turning suddenly to undef and back again depending on subfunction call
by flexvault (Monsignor) on Feb 25, 2013 at 18:55 UTC

    tobias_hofer,

    Put an extra set of brackets in the script. '{' after the package name, and a '}' the end of the script. Now, everything is in scope, so nothing should be 'undef' unless you didn't define them.

    Hope this helps...Ed

    "Well done is better than well said." - Benjamin Franklin

      I gave a try but there is no change in the debugger-view. Guess its up to the eclipse-plugin or debugger as using print statements is working fine.

      Thanks a lot!
      Tobias

        tobias_hofer,

        Just a little trick on using 'print' statements and debugging. (Note: I'm using *nix boxes) At the beginning of all of my packages, I define (actually copy the code) the following:

        ###################################################################### +# # DEBUG ==0 {no debugging}, ==1 {debugging}, >=2 {greater debugg +ing} ###################################################################### +## # our $Debug = 0; our $DLOG; ## Production our $Debug = 4; our $DLOG; ## Testing if ( $Debug ) { my $logFile = "MyLog_$$"; ## Good for multi-user testing open($DLOG,">",$logFile) || die "Cannot open $logFile:$!"; print $DLOG "############################# ".scalar localtime() +."\nStart. . . \n"; } else { open $DLOG, ">>", "/dev/null" ); }

        At different places in the code, if I have something going wrong, I insert statements like:

        for my $key { sort keys %Hash ) { ... do something ... if ( $Debug >= 4 ) { print $DLOG "Hash:\t$key\t|$Hash{$key}|\n +"; } }
        Once you get it working, all you have to do to stop printing to the log, is change the '4' to a '5' and the print won't be executed. When computers were much slower than today, I used to take them out for production, but now I leave them in and change the global '$Debug' to '0'.

        The advantage to doing this is if you have a production problem, you can turn the debugging on and get some help finding the problem. :-)

        There have been times when I've had a debug statement after every line of code to figure out what was going wrong. It's usually a typo or some other simple mistake, but without the debug info, you just don't see it. ( I always use strict and warnings, but sometimes things get through. )

        Always name the output so you can use your editor to search on the print statement. Notice that I put '|' around the variables to help see if it's undefined or "". You can also print to STDERR when your getting warnings. One time I was getting a couple 100K warnings for a script and by printing to STDERR, I was able to see the start and end of the problem in the loop. If your not testing a multi-user or multi-tasking package you don't need the '$$'. That's just so you don't have to lock/unlock the log file.

        Good Luck...Ed

        "Well done is better than well said." - Benjamin Franklin