PREVIOUS  TABLE OF CONTENTS  NEXT 

Guts - A Bug Hunt

Chip Salzenberg

Packages Used
Just Perl

"Is this going to be a stand-up fight, or a bug hunt?"
- CPL. HUDSON

Easy debugging of Perl programs has been a standard feature of Perl for a very long time. The Perl debugger - written in Perl! - is invoked with the -d flag.

This column is not about the -d flag.

This column is about the -D flag. This flag is your gateway to a set of debugging behaviors inside Perl's guts. If you're up against a tough set of bugs and you can't figure out where they're coming from, then -D may be just what the sergeant ordered.

STEP ONE: ENLIST

"... every meal a banquet, every formation a parade!" - SGT. APONE

Not all Perl binaries will let you use the -D flag. The code to support it makes the Perl binary a bit larger and slows down execution just a hair. Since Larry is loathe to enlarge or slow Perl, your binary only includes support for -D if you explicitly compiled it with the -DDEBUGGING option.

How do you know whether your Perl binary was compiled with -DDEBUGGING? You can tell by examining the output of perl -V. The last section of perl -V output is "Characteristics of this binary." If you have a fairly recent version of Perl, the first line in that section will be "Compile-time options"; if that line includes the word DEBUGGING, then your Perl supports -D.

STEP TWO: KNOW YOUR WEAPONS

"I'd like to introduce you to a personal friend of mine."
- CPL. HICKS

Perl is too complex and juggles too many eggs to have just one debugging flag. And in fact -D isn't really just one flag.Rather, it's a prefix that lets you turn on multiple debugging flags. The individual flags you should use depend on what aspect of Perl you're trying to debug (or understand). Get to know them, or you might end up using a pulse rifle when you need a flamethrower.

Below is a list of debugging flags accessible via -D, as listed in the perlrun documentation. Each flag has a letter that you can put after the -D to turn on a particular type of debugging. You can combine them by listing multiple letters. Each flag also has a number, so if you prefer setting debugging flags by number instead of by letter (but why?) follow -D with the sum of the numbers you want.

LETTER      NUMBER         MEANING

p             1             Tokenizing and parsing
s             2             Stack snapshots
l             4             Context (loop) stack processing
t             8             Execution trace
o             16            Method and overloading resolution
c             32            String/numeric conversions
P             64            Print preprocessor command for -P
m             128           Memory allocation
f             256           Format processing
r             512           Regular expression parsing and execution
x             1024          Syntax tree dump
u             2048          Tainting checks
L             4096          Memory leaks (no longer supported)
H             8192          Hash dump - usurps values()
X             16384         Scratchpad allocation
D             32768         Cleaning up

What do these flags, and their output, mean? This article examines them, beginning with the most useful.

-Dt: TRACE EXECUTION

Perl is a compiled language. Although the technology for separating compilation from execution of Perl code isn't quite ready for prime time, it's still true that any given Perl program is fully compiled before its execution begins. The output of the Perl compiler isn't machine code, but an intermediate form designed for execution at reasonable (though not machine-code) speed. This scheme is rather like Java's, except that Perl doesn't save its intermediate form after compilation; it just executes it.

When the -Dt option is specified, Perl prints to the standard error (STDERR) a record of the source file, line number, and opcode name for each opcode it executes. Let's say the file foo contains this Perl program:

$a = 1;
print $a + 1;

We can see the opcodes executed by Perl with -Dt.

$ perl -Dt foo perl -Dt foo
EXECUTING...

(foo:0)     en!ter
(foo:0)     nextstate
(foo:1)     const(IV(1))
(foo:1)     gvsv(main::a)
(foo:1)     sassign
(foo:1)     nextstate
(foo:2)     pushmark
(foo:2)     gvsv(main::a)
(foo:2)     const(IV(1))
(foo:2)     add
(foo:2)     print
(foo:2)     leave

These opcodes are described below.

The -Dt option is helpful if your Perl binary is dumping core or otherwise misbehaving, and you want to find out what part of your program is triggering the problem.

-Ds: STACK SNAPSHOTS

Perl is not a stack-based language like, say, Forth.( For the Forth aficionados reading this column, I offer my idea of the ideal bumper sticker: "YOU FORTH LOVE IF HONK THEN." ) But under the hood, the Perl runtime is a stack machine: Each opcode takes operands from a stack of values and leaves its results on that same stack of values. (There are a few exceptions for efficiency reasons.)

When run with the -Ds option, Perl prints a snapshot of the values on the stack before the execution of each opcode. This is difficult to read without -Dt, so we'll combine them for this example, just as we would in real life:

$ perl -Dts -le '$a = 1; print $a'
  =>
(-e:0)   enter
  =>
This opcode comes before the sample code - there's an
enter at the start of every program. (Or of any scope that
requires cleanup on departure, for that matter.)
(-e:0)   nextstate
  =>
(-e:1)   const(IV(1))
  => IV(1)
(-e:1)   gvsv(main::a)
  => IV(1) UNDEF
(-e:1)   sassign
  => IV(1)

This is the first statement: nextstate clears the already empty stack; const pushes a constant (the integer 1) onto the stack; gvsv pushes $a (which has no value yet); and sassign performs the scalar assignment to $a, leaving the value assigned on the stack. Now for the print $a:

(-e:1)   nextstate
  =>
(-e:1)   pushmark
  => *
(-e:1)   gvsv(main::a)
  => * IV(1)
(-e:1)   print
1
  => SV_YES

nextstate clears the stack; pushmark pushes a mark, which shows up as an asterisk. List operators like print use marks to keep track of the number of arguments they're passed. Next, gvsv pushes $a (which now has the value one); and finally, print prints everything to the right of the mark, pushing a true value onto the stack to indicate success.

In this case, that true value is the internal constant SV_YES. The named constants you'll see in stack snapshots are SV_YES ('1'), SV_NO (the empty string), and SV_UNDEF (undef).

(-e:1) leave

There's always a leave at the end of the program. (Or of any scope that requires cleanup on departure.)

-Dx: SYNTAX TREE DUMP

As you've seen, the -Dt and -Ds options reveal the runtime execution of Perl's opcodes. Sometimes, watching the sequence of execution is less revealing than an examination of the tree of OP structures created by the compiler.

When the -Dx option is specified, Perl prints (to standard error) the entire OP tree just before it's executed. The format of -Dx output is:

{
## TYPE = optype ===> next_index
   FLAGS = (flags)
   kids
}

Here, optype is the OP's type - enter, const, sassign, and so on. The ## placeholder marks the location of the OP index, which is a small integer. To the right of the arrow is next_index, the index of the next OP to be executed. (The OP tree is singly-linked in order of execution: each OP structure has an OP op_next pointer.)

If the OP has parameters or other subsidiary OPs, they are listed where the word kids appears. They're indented to show the nested structure of kids of kids.

The FLAGS line lists various OP flags by name. Most OP flags are specific to particular optypes, but a few are common to all OPs. I'll discuss them now.

VOID, SCALAR, LIST. These flags indicate how many values the OP may produce: either nothing or one value (which will be ignored); one value; or any number of values, respectively.
KIDS. The OP has kids.
REF. The OP should return a reference to the things it accesses, instead of their contents.
MOD. The OP should modify (or prepare to modify) the things it accesses.

Here's a real-life example of the output of -Dx:

$ perl -Dx -le '$a = 1' perl -Dx -le '$a = 1'
{
6 TYPE = leave ===> DONE
  FLAGS = (VOID,KIDS,PARENS)

This is typical: Since kids are almost always executed before their parents, the first OP you see is usually the last one executed. That's why the first OP in most -Dx outputs is leave. (Note that the leave has no next_index because after the leave executes there's nowhere else to go - your program is finished.)

    {
1        TYPE = enter ===> 2
    }

And as the first kid of the top OP, this enter is the first OP executed.

    {
2     TYPE = nextstate ===> 3
      FLAGS = (VOID)
      LINE = 1
    }
    {
5     TYPE = sassign ===> 6
      FLAGS = (VOID,KIDS,STACKED)
      {
3       TYPE = const ===> 4
        FLAGS = (SCALAR)
        SV = IV(1)
      }
      {
        TYPE = null ===> (5)
          (was rv2sv)
        FLAGS = (SCALAR,KIDS,REF,MOD,SPECIAL)
      {
4         TYPE = gvsv ===> 5
          FLAGS = (SCALAR)
          GV = main::a
      }
    }
  }
}

Note that the sassign (scalar assignment) operator has the VOID flag, because the value of the assignment statement as a whole is thrown away. That wouldn't be true if the assignment were part of a larger expression, like $b = $a = 1.

Note also that Perl's optimizer eliminated an rv2sv OP and left a null in its place. That has no effect on runtime efficiency, since the execution order is nextstate, const, gvsv, sassign - none of the OPs has that null as its next_index.

A complete interpretation of -Dx output requires detailed understanding of the OP tree structure. But even without that level of detail, -Dx is still useful in figuring out why Perl isn't executing your code the way you think it should.

-Dr: REGULAR EXPRESSION PARSING AND EXECUTION

Regular expressions are central to Perl programming. They are indispensable. They can also be hard to write, harder to read, and impossible to debug.

The relatively recent /x regex modifier has reduced this problem somewhat by allowing programmers to include spaces in their regular expressions for clarity. However, it's still difficult sometimes to figure out exactly what a regular expression means and how it works (or doesn't work).

Enter -Dr. When run with -Dr, Perl prints a description of each regular expression it compiles, and a running commentary on each regular expression it executes.

Before you get your hopes too high, I should warn you that -Dr is nowhere near the pretty animated pictures of regular expressions in action that some people have asked for. But it's a way to see every detail of your regular expressions, and to pinpoint exactly where a regular expression might have gone wrong.

(Side note: If you want enduring fame, and if the thought of wading hip deep into large quantities of amazingly hairy C code does not send you running in terror, consider writing a friendly animated illustrator for regular expressions. Just don't charge me for any therapy you need as a result.)

Let's suppose you are scanning a bunch of old Usenet articles, and you're looking for old-style UUCP bang paths, like seismo!gatech!usfvax2!ateng!chip (one of my old email addresses). You might start with a pattern like this:

/ ( \w+ (?: !\w+ )+ ) /x

Which means "a hostname, followed by one or more repetitions of an exclamation point followed by a hostname," where "hostname" here means "one or more alphanumerics or underscores." This works for many cases, but it doesn't match Larry Wall's old address, which always ends with ...!jpl-devvax!lwall. That's no good. But how can we fix this bug if we don't understand it?

This is where -Dr comes in. However, before actually using -Dr to debug a regex problem, you should create a small test program to exercise it. The output of -Dr can be astoundingly verbose; separating the wheat from the chaff is hard enough without irrelevant regexes cluttering things further.

A reasonable test program for our situation might be:

$_ = 'seismo!jpl-devvax!lwall';
print $1, "\n" if / ( \w+ (?: !\w+ )+ ) /x;

This program, when run, outputs only devvax!lwall. But why did the pattern match only part of the target string? This is the kind of question that -Dr was designed to answer.

When run with -Dr, Perl generates some debugging output before execution, and more during execution. The preexecution output is a listing of the compiled representations of all of the program's regular expressions - at least, all of them that can be compiled ahead of time. Perl always compiles regexes down to compact bytecodes so they can be executed faster - of course, patterns constructed at runtime can't be compiled until they're used.

With -Dr and our test program, we'll see this interpretation of the test regex:

1:     OPEN1(3)
3:         PLUS(5)
4:              ALNUM(0)
5:         CURLYX {1,32767}(12)
7:              EXACT <!>(9)
9:              PLUS(11)
10:               ALNUM(0)
11:             WHILEM(0)
12:        NOTHING(13)
13:     CLOSE1(15)
15:     END(0)

This is a listing of the bytecodes in the compiled regex. Each bytecode is a fundamental unit of regex execution. This listing shows each bytecode with its byte position on the left, then its name, then any parameters, then the position of any related bytecode in parentheses. (A zero means there is no related bytecode.)

The outermost construct is an OPEN1/CLOSE1 pair; these specify the beginning and ending of the first set of memory parentheses, which you can think of as \1 or $1. (In this pattern, the first set is also the only set.)

Inside the OPEN1/CLOSE1, the first item is a PLUS (one or more repetitions) controlling an ALNUM (single alphanumeric character). This combination means "one or more alphanumerics," i.e. the leading hostname in the bang path.

After the leading hostname is CURLYX{1,32767}(12). It specifies no less than one and no more than 32767 repetitions of all bytecodes up to but not including #12. (As it happens, #12 is a NOTHING put there as a placeholder.)

This bytecode is named CURLYXbecause the general notation for repeat counts uses curly braces - X{N,M} means "no less than N and no more than M X's".

(You may wonder about the 32767, since that wasn't in the pattern. One of the limitations of Perl's current regular expression engine is that repeat counts cannot exceed 32767, even when they are merely implied. I hope that this limitation will be removed eventually.)

Within the CURLYX loop is an EXACT<!>, which matches the exact string '!'; then another PLUS/ALNUM pair, which matches another sequence of one or more alphanumerics. Together, these match a bang followed by a name (host-name or username).

Because the EXACT, PLUS, and ALNUM are inside the CURLYX loop, they may be applied many times in a successful match - which is just fine, since we want the regex to match both long and short bang paths.

Further down in the output, we see Perl executing the test program. Soon thereafter, we see the regular expression engine applying the test regex to the test string:

EXECUTING...
Matching ' ( \w+ (?: ! \w+ )+ ) ' against 'seismo!jpl-devvax!lwall'
    Setting an EVAL scope, savestack=3
     0 <> <seismo!jpl-d> | 1: OPEN1

This line illustrates the general format of the trace that -Dr generates. First is the current offset in the target string, which usually starts out at zero. Next are small portions of the target string found just to the left and to the right of the current position, printed inside angle brackets. Finally, the bytecode position and bytecode name about to be executed.

The job of regex debugging largely consists of keeping clear in your mind two things: the position in the target string where the regex engine is attempting to match, and the byte codes that the regex engine is executing.

Now some more of the output:

0 <> <seismo!jpl-d> | 3: PLUS
                  ALNUM can match 6 times out of 32767...

The first \w+ matches six characters: seismo. So far, so good.

Setting an EVAL scope, savestack=3
6 <eismo> <!jpl-de> | 5: CURLYX {1,32767}
6 <eismo> <!jpl-de> | 11: WHILEM
                       0 out of 1..32767 cc=bffff8e8

We begin the !\w+ loop...

6 <eismo> <!jpl-de> | 7: EXACT <!>
7 <ismo!> <jpl-dev> | 9: PLUS
                ALNUM can match 3 times out of 32767...

Whoa! Only three? We expected ALNUM to match ten characters: jpl-devvax. Yet it only matched three: jpl. It stopped at the dash. Why?

Aha! The test pattern expects \w+ to match hostnames, but \w doesn't match dashes. There's the bug.

Sure enough, when we change the test program to this, it prints the entire path.

$_ = 'seismo!jpl-devvax!lwall';
print $1, "\n" if / ( [-\w]+ (?: ! [-\w]+ )+ ) /x

Using -Dr to its fullest requires an understanding of all regex bytecodes. Such understanding is, to say the least, rare; Mastering Regular Expressions is a thick book for a reason.

However, even a minimal knowledge of the internals of Perl's regexes - such as you now have from reading this section! - can be enough to make some use of -Dr. And there's no better way to learn the in and outs of regexes than to play around a little. So relax and have a bit of fun with -Dr. When the brain worms start digging in, you'll hardly notice.

-Do: METHOD AND OVERLOADING RESOLUTION

Object-oriented Perl programming is fairly easy to learn. However, debugging object-oriented Perl presents unique challenges. Sometimes the pronounced modularity of object-oriented code results in failures that are hard to track down.

The -Do flag assists with such difficulties by reporting whenever a class or object lookup occurs.

For example, this code produces a runtime failure:

sub Base::foo {
  print "hi";
}

@Derived::ISA = qw/Bake/;          # bug here - typo!
Derived->foo;

Due to the typo in @Derived::ISA, the foo() method is not found.

In a small program this bug is trivial to find; in a large program it isn't. However, with -Do, the nature of the problem becomes much clearer. Let's call our program otest:

(otest:7) Looking for method foo in package Derived
(otest:7) Looking for method foo in package UNIVERSAL
(otest:7) Looking for method AUTOLOAD in package Derived
(otest:7) Looking for method AUTOLOAD in package UNIVERSAL
Can't locate object method "foo" via package "Derived"
                              at /u/home/chip/c5 line 7.

The first thing you'll notice is that Base isn't mentioned at all. Perl doesn't realize that Derived is derived from Base. This points a finger at the variable that specifies derivation, namely, @Derived::ISA. And there's the bug.

When I prepare these columns, I am occasionally surprised by Perl's behavior. Now is one of those times.

The output of the test program above should mention the misspelled package name Bake, which after all appears in @Derived::ISA. Experiments reveal that -Do only ever mentions searching of packages that are at least declared. As a result, misspelled class names will not appear in -Do output - a decidedly strange state of affairs for a debugging flag! I think this is a bug in Perl, and if I have my way, it will be fixed by the time this column goes to press.

-Dl: CONTEXT (LOOP) STACK PROCESSING

Two kinds of scoping affect the behavior of Perl code. Lexical scoping relates to the physical placement of the code in the surrounding program. For example, this matters to most pragmas (e.g. use strict) and the visibility of my variables (also called "lexical variables" - and now you know why).

Dynamic scoping relates to the flow of control that led to a given bit of code being executed. In a word, it's the code's temporal placement - what ran before it, what is in progress when it runs, and what hasn't yet been reached.

When -Dl is used, Perl prints a record of the dynamic scopes. The stack of pending scopes is vital to the runtime behavior of Perl control structures like subroutines and loops.

Here's a minimal example of -Dl output:

$ perl -Dl -le 'if (@ARGV) { print @ARGV }
          ' Hello perl -Dl -le 'if (@ARGV) { print @ARGV }' Hello
  EXECUTING...
  Entering block 0, type BLOCK
  Hello
  Leaving block 0, type BLOCK

Every Perl program is surrounded by an implicit block, so what you see here is the minimal output of -Dl. Now that you know this, you might be surprised not to see two BLOCK messages, since the print statement is in an if block. However, Perl elided the second BLOCK as an optimization; it does this whenever the block's contents don't require run-time tracking for cleanup. To force a BLOCK context, we need only put something in the block that would require cleanup - say, a my declaration:

$ perl perl -Dl -Dl -le -le 'if 'if (@ARGV) 
            {my @a = @ARGV; print @a}' Hello (@ARGV) 
            {my @a = @ARGV; print @a}' Hello
EXECUTING...
Entering block 0, type BLOCK
Entering block 1, type BLOCK
Hello
Leaving block 1, type BLOCK
Leaving block 0, type BLOCK
-Dr prints a description of each
regular expression it compiles.

The output of -Dl may include these scope types:

BLOCK. A code block, usually surrounded with { } - but not a naked block.
LOOP. A loop: while/until, for, foreach, or a naked block. Naked blocks are blocks of code surrounded by bare {}. Perl does not consider them to be BLOCKs, but LOOPs, because naked blocks are degenerate loops that by default execute exactly once. This fact allows you to use redo and last in a naked block to restart and exit it, respectively.
SUB. A subroutine call.
EVAL. Code executed via the eval operator, either eval BLOCK or eval STRING.
SUBST. The replacement expression in the substitution operator s///. If the replacement string is complex enough to require calculation at runtime - perhaps because it interpolates match variables like $1 or because it's a full expression invoked via s///e - Perl uses the special SUBST context to keep track of the replacement and clean up if it dies.

-Dp: TOKENIZING AND PARSING

As we discussed in (uncomfortable) detail last issue, tokenizing is the process of taking the textual input of a Perl program and figuring out what it means - i.e. figuring out that print $a+$b is really print, $a, +, and $b, in that order.

The next step is parsing: figuring out the meaning of those tokens according to the language grammar. The code that does this job is called, unsurprisingly, the parser.

To avoid a lot of unnecessary grunt work, Larry used the yacc program to generate Perl's parser. (Well, actually he chose a clone of yacc called byacc; but that doesn't matter right now.) All yacc-generated parsers include optional debugging code. That debugging code is compiled only if the YYDEBUG macro is defined, which happens automatically when Perl is compiled with -DDEBUGGING. And even then, it generates debugging output at runtime only if the variable yydebug has a non-zero value. And that's one of the things that happens when you use -Dp.

When compiled and enabled, yacc debugging code prints each token returned by the tokenizer (again, to standard error), as well as any meaning that the parser gives it. And since Perl's tokenizer is so closely tied to the grammar, it also generates occasional -Dp debugging messages.

The advantage of -Dp is that it helps track down obscure syntax errors by showing what Perl saw, token by token. Some parsing errors are difficult to track down without it. The disadvantage of -Dp is that its output is, well, voluminous. Be sure to redirect STDERR to a file when you use -Dp. Here's an example of -Dp, with interspersed commentary:

$ perl -Dp -le 'print $INC[0], "\n"' perl -Dp -le 'print $INC[0], "\n"'
yydebug: after reduction, shifting from state 0 to
         state 2
yydebug: state 2, reducing by rule 7 (lineseq :)
yydebug: after reduction, shifting from state 2 to
         state 3

In order to make sense of these first three lines of the output - particularly the state numbers - you need to run byacc yourself with its -d option, which creates a file called y.output. Then you need to use that file's list of state numbers as a cross-reference. Assuming you don't go to that much trouble, the "shifting" messages will make no sense to you, so I'll omit them from the rest of this section. For yacc-generated parsers, the term "reduce" roughly means "decide the meaning of what's been seen." So from the bit of output quoted above, it's apparent that Perl's grammar has decided - without having seen anything yet - that the program starts with a sequence of lines ("lineseq") and has decided that it's looking for zero or more such lines. This always happens. More debugging output:

### Tokener expecting STATE at

This message comes from the lexer. Perl's lexical analysis is heavily dependent on context, so the lexer has to be primed to know what to look for. This message lets us in on that detail. In this case, the lexer is looking for the beginning of a new STATEment.

yydebug: state 3, reading 286 (LSTOP)

Here parser has read its first token from the lexer: the integer 286, which has the name LSTOP, for list operator. This one happens to be the print in our sample code.

yydebug: state 3, reducing by rule 44 (label :)

This reduction is the parser's decision that there must not be a label on this statement. (A label is a WORD and a colon, and since there's no colon, there must not be a label.)

### Tokener expecting REF at $INC[0], "\n"

Expecting a REF is usual after a list operator; it's how the tokener grabs, say, the optional filehandle name after print or the optional subroutine name after sort.

yydebug: state 43, reading 36 ('$')
yydebug: state 62, reading 257 (WORD)
yydebug: state 87, reducing by rule 173
         (indirob : WORD)
yydebug: state 136, reducing by rule 168
         (scalar : '$' indirob)
### Tokener expecting OPERATOR at [0], "\n"

At this point, Perl has seen print $INC and figured out that it's an LSTOP followed by what looks like a scalar. However, there are still several possible interpretations, depending on what comes next. If the next token is a semicolon, then it's a print of the scalar variable $INC. If the next token is an operator - which as you can see is what the lexer is primed to find - then it's a print of whatever comes next to the file-handle named in $INC (e.g. print $INC @stuff). But as it happens, the next token is neither of those:

yydebug: state 111, reading 91 ('[')
### Tokener expecting TERM at 0], "\n"

Having found the left square bracket, Perl knows that it's looking for an array element expression, so now it knows that $INC isn't a filehandle. Therefore, the lexer expects a TERM, that is, an array subscript expression.

yydebug: state 170, reading 260 (THING)

Yes, "THING". To simplify its interface, Perl's lexer returns strings, numbers, and other miscellaneous values under the catch-all name THING. Each THING token carries with it an OP tree - a sequence of fundamental Perl operations. This particular THING carries an OP of type OP_CONST (constant value), attached to an SV (scalar value) of zero.

Well, there's more - lots of work goes into parsing even short Perl expressions. But what we've discussed so far should be enough to help you figure out what Perl thinks it's seeing when you and Perl disagree.

"AND THE REST..."

There are more debugging flags available via -D, but space and sanity prevent their full description in this column. In brief, they are:

-Dc: String/numeric conversions. This prints a diagnostic whenever a string is automatically converted to a number, or vice versa.

(I think I've found a bug in the way this flag works. The first field of its output is a hex number; I think it's supposed to be a string. If so, it'll probably be fixed by the time you read this.)

-DD: Cleaning up. This reports cleanup of objects (in the "object-oriented" sense of "objects") at program termination. When a Perl program terminates in an orderly fashion - no signals or core dumps - Perl does its best to find all objects that haven't yet been DESTROYed, and destroy them. This lets Perl programs use object destruction to trigger important cleanups.

-Df: Format processing. This shows details of field processing and pagination for Perl's formats. If you use formats, this flag might help you understand how Perl executes them. However, the diagnostics it generates are designed for debugging Perl, not for debugging your programs, so it probably won't help much.

-Du: Tainting checks. This prints a (minimal) diagnostic whenever a potentially dangerous operation finds its inputs tainted (untrustworthy). See the perlsec documentation for a discussion of tainting and its uses.

-DP: Print preprocessor command for -P. This shows the command line executed for the -P flag, which runs your program through the C preprocessor. If you use -P, you understand why you might possibly need this. But you probably don't use -P. Good.

-DH: Hash dump - usurps values(). This reports on hash internals when the values() operator is used. Unless you want to understand or debug Perl's implementation of hashes, you won't need this.

-Dx: Scratchpad allocation. This flag shows the allocation and use of scratchpad slots. Unless you want to track down bugs in Perl's use of my variables and temporary values, you won't need this.

-Dm: Memory allocation. This reports on every low-level memory activity - allocation, resizing, and freeing. Perl does a lot of this. Expect a lot of output. You might find this flag useful if you think Perl (or a loaded extension) is committing memory allocation violations, but you'll need to write a program to digest the diagnostics because of their sheer volume.

-DL: Memory leaks. This identifies any memory allocated but not freed when Perl exits. It doesn't work with all versions of Perl, and there may be a few false positives in the report. However, large numbers of leaked memory blocks indicate a serious problem.

ROCK AND ROLL

El Riesgo Siempre Vive
- WRITTEN ON PVT. VASQUEZ'S ARMOR

Sometimes you'll be doing something important in Perl and your programs just won't work. You'll be surprised at every turn. You'll start to feel like you're in a pitched battle, out-numbered by bugs hard to find and even harder to kill. When that happens, remember these debugging flags. They may just turn your desperate last stand into a run-of-the-mill bug hunt.

__END__


Chip Salzenberg was coordinator and primary programmer for Perl 5.004. His major solo project was Deliver, the free email local delivery agent that allows flexible, safe, and reliable message handling. His hobbies include patching Perl, tending to his six parrots, and memorizing Mystery Science Theater 3000 episodes.
PREVIOUS  TABLE OF CONTENTS  NEXT