bug-m4
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: dangling pointer bug and proposed patch


From: Eric Blake
Subject: Re: dangling pointer bug and proposed patch
Date: Wed, 10 May 2006 22:03:24 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

Answering myself,

> First, I claim that some of the behavior you call unspecified in section 2
> is actually specified.  For example, you mention
> 
> define(`f',`one')f(define(`f',`two'))
> 
> According to POSIX, "Macros may have arguments, in which case the
> arguments shall be substituted into the defining text before it is
> rescanned."  So the argument "define(`f',`two')" is expanded to void, then
> plugged into the defining text of f (which is now `two'), resulting in
> "two" as you note.

I went one step further, and compared against Solaris 8's /usr/
{ccs,xpg4}/bin/m4, with surprising results:

In a slight modification of your third example,

define(`f',1)f(pushdef(`f',2)f(define(`f',3)))f`'popdef(`f')f

GNU m4 gives "131", but Solaris gave "33f".  This seems like a Solaris bug, 
since the pushdef failed to preserve the definition of f being "1".

Then, on your proposals in section 3,

define(`f',1)f(undefine(`f')2)f`'popdef(`f')f

Your proposal would give "f(2)ff", but Solaris gave "1ff".  In other words, 
when a macro is deleted, they used the definition that was in place just prior 
to the deletion.

define(`f',1)f(pushdef(`f',2)f(undefine(`f')3))f`'popdef(`f')f

Your proposal would give "f(f(3))ff", but Solaris gave "1ff"; again, regardless 
of whether Solaris m4 has a pushdef bug, the outermost f was deleted, so its 
definition of "1" prior to the deletion was used.

A slight modification:

define(`f',`1$1')f(pushdef(`f',2)f(undefine(`f')3))f`'popdef(`f')f

Here, your proposal would give "f(f(3))ff", since both active definitions of f 
are deleted; but Solaris gave "12ff", meaning that the innermost f remembered 
his expansion of "2", and the outermost f remembered his expansion of "1$1".

> However, I'm still not sold on your analysis in section 3 that 
> 
> define(`f',`one $1')f(pushdef(`f',`two $1')f(popdef(`f')three)) 
> 
> should result in "one one three".  I think it might be more reasonable if 
> it resulted in "one f(three)", where the innermost expansion of f uses the 
> innermost definition of f at that time (it is undefined, resulting in 
> "f(three)") rather than falling back to an outer definition (resulting in 
> "one three"). 

Oops, looking at that, I'd better modify my argument.  Your proposal would 
trace like:
f(pushdef(`f',`two $1')f(popdef(`f')three)), f1 defined
f(f(popdef(`f')three)), f1 defined and active, f2 defined
f(f(three)), f1 defined and active, f2 deleted and active
f(one three), f1 defined and active, f2 expanded using f1's definition
one one three, f1 expanded using f1's definition
one one three, rescan found no more macros

Where mine would like like:
f(pushdef(`f',`two $1')f(popdef(`f')three)), f1 defined
f(f(popdef(`f')three)), f1 defined and active, f2 defined
f(f(three)), f1 defined and active, f2 deleted and active
f(f(`three')), f1 defined and active, f2 expanded as $0($@)
f(f(three)), rescan found f, f1 defined and active twice
f(one three), f1 defined and active once, f1 expanded using f1's definition
one one three, f1 defined, f1 expanded using f1's definition
one one three, rescan found no more macros

So we do get the same results on this test case, but through different paths.  
How to expose the difference?

define(`lf',`zero')
define(`f',`one $1')f(pushdef(`f',`two $1')l`'f(popdef(`f')three))

Your way would see an intermediate "f(lone three)", resulting in a final "one 
lone three", where my way would see an intermediate "f(lf(`three'))", resulting 
in a final "one zero".


Now, how does Solaris do on this?

define(`f',`1$1')f(pushdef(`f',`2$1')f(popdef(`f')3))f(4)popdef(`f')f(5)

Either your or my proposal would give "11314f(5)", but Solaris gave "12314f
(5)", since their expansion of "f(popdef(`f')3)" recognized that even though 
that level of f was just deleted, it had the definition "2$3" at the time.

Now, as to your comparison to the C pre-processor:

Your first example is not quite fair; it would be better as cpp:
#define f(x) one
f(
#undef f
#define f(x) two
three)

giving "one", compared to m4:
define(`f'),one)
f(undefine(`f')define(`f',two)

giving "two".  Here, Solaris agreed with your analysis, although it means they 
are a little inconsistent with their earlier behavior of remembering what the 
definition used to be before it was deleted.

But on the second example:
#define f(x) one x
f(
#undef f
two)

vs.:
define(`f',`one $1')
f(undefine(`f',two)

both gave "one two" on Solaris.

So, maybe the best thing now would be to ask the Austin group for clarification 
on the intended POSIX semantics, whether one behavior or the other must be 
supported, or whether it is implementation defined; at which point we can then 
revisit what this patch really should be.

-- 
Eric Blake






reply via email to

[Prev in Thread] Current Thread [Next in Thread]