On Sat, Dec 08, 2001 at 09:48:13PM -0800, Guy Harris wrote:
> It appears that "gen_arth()" frees "a1->regno" but not "a0->regno" - it
> just overwrites "a0->regno".
> 
> I'll have to see whether the actual *code* overwrites it, so that the
> old value in "a0->regno" can be freed.

It doesn't - it's overwriting the "register" (scratch memory location)
referred to by "a1->regno".

If a given "struct arth" is used more than once, so that you can't
overwrite its "register" until the *last* load of it is generated, it's
not safe to free up "a0->regno".

On the other hand, it's not clear that it's safe to free up "a1->regno",
either, unless there's some guarantee that if a given "struct arth" is
passed as the third argument to "gen_arth()", it's never passed to
anything else to use.

"struct arth"s are generated by:

        gen_load()

        gen_loadlen()

        gen_loadi()

        gen_neg()

        gen_arth()

Inside the parser, a given "$n" that refers (points) to a "struct arth"
is never passed more than once to any function, so the parser can't
(unless I'm completely missing something) generate more than one
reference to a "struct arth".

"gen_inbound()" is the only routine in "gencode.c" that calls any of the
"gen_load*" routines; it also doesn't use the results of any of those
calls more than once.  Nothing in "gencode.c" uses "gen_neg()" or
"gen_arth()".

The routines that take "struct arth *"s as arguments don't store that
argument anywhere.

So it *appears* that a "struct arth" won't be used more than once, and
therefore that it's safe to add "free_reg(a0->regno);" before the
"free_reg(a1->regno);" in "gen_arth()" ("gen_relation()" frees the
registers for both of its "struct arth *" arguments in that fashion).

This would break, of course, if somebody added new code that *did* save
a "struct arth *" and used it more than once; if they did that, we'd
probably have to treat the elements of the "regused[]" array as
counters, not booleans, with "alloc_reg()" still setting it to 1,
"free_reg()" decrementing it (aborting if it's 0, as that means you're
freeing a free register), and another routine bumping the use count, for
use by routines that use a "struct arth *" more than once.

A patch to change "gen_arth()" is attached; Ken, could you try applying
that patch (after removing the "reset_regs()" stuff), and see if it

        1) plugs the leak caused by repeated compilation;

        2) plugs any leaks discovered by compilation of a sufficiently
           complex expression (if you've found any of those);

        3) breaks anything you notice?
Index: gencode.c
===================================================================
RCS file: /tcpdump/master/libpcap/gencode.c,v
retrieving revision 1.160
diff -c -r1.160 gencode.c
*** gencode.c   2001/11/30 07:25:48     1.160
--- gencode.c   2001/12/09 06:01:04
***************
*** 3589,3594 ****
--- 3589,3595 ----
        sappend(a1->s, s0);
        sappend(a0->s, a1->s);
  
+       free_reg(a0->regno);
        free_reg(a1->regno);
  
        s0 = new_stmt(BPF_ST);

Reply via email to