NetBSD-Bugs archive

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

toolchain/53034: make crash from archive member handling



>Number:         53034
>Category:       toolchain
>Synopsis:       make crash from archive member handling
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    toolchain-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Feb 17 06:25:00 +0000 2018
>Originator:     David A. Holland
>Release:        NetBSD 8.99.9 (20181207)
>Organization:
>Environment:
System: NetBSD macaran 8.99.9 NetBSD 8.99.9 (MACARAN) #45: Thu Dec 7 18:18:48 EST 2017 dholland@macaran:/usr/src/sys/arch/amd64/compile/MACARAN amd64
Architecture: x86_64
Machine: amd64
>Description:

Certain makefiles involving archive member specifications cause SIGSEGV
when in compat mode. This came up via a FreeBSD pr: 
   https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=225946

The makefile below is sufficient to reproduce the problem. Clearing
the builtin suffixes makes investigation easier.

The problem that causes the crash is that $(.TARGET) (aka $@) never
gets set for foo.c, so when make goes to set $(.IMPSRC) (aka $<) it
crashes. This only happens with both a suffix rule and an explicit
rule for foo.o, because it only crashes when $(.IMPSRC) is set the
second time; owing I guess to internal peculiarities of var.c the
first time the null value is converted to "" and only when trying to
*change* the value is there a crash.

However, that's unimportant; the question is why $(.TARGET) doesn't
get set on foo.c.

This is considerably more complicated and relies on the presence of a
dependency chain that goes through an archive member.

In particular, what happens is as follows:

* Make_ExpandUse in make.c examines the entire tree that's going to
get built. The primary purpose of this is to implement the .USE
(mis?)feature, but one of the other things it does is make sure
$(.TARGET) is set on every target that's going to be made.

* Under normal circumstances, without the archive member on the RHS of
the lib.a rule (but instead just "foo.o") it will examine all, then
lib.a, then foo.o, and then because foo.c depends on foo.o, at the
bottom of the loop when examining foo.o it will add foo.c to the list
of targets to process and then process it as well, so $(.TARGET) on
foo.c gets set.

* When the dependence chain goes through the archive member spec,
however, the archive member case of the suffix rule mechanism is what
creates the GNode for foo.o (in SuffFindArchiveDeps) and this marks it
OP_MEMBER | OP_JOIN | OP_MADE.

* Because it's OP_MADE it won't be built, apparently. (I'm not sure
how this logic is supposed to work in the wild when actually working
with real archive members.) It still depends on foo.c, but this causes
Make_ExpandUse to not add its children (thus, foo.c) to the list of
targets it examines. This causes $(.TARGET) to not get set on foo.c.

* In spite of this, foo.o gets built, and this causes foo.c to be
looked at, and that's the point at which trying to set $(.IMPSRC)
crashes.

* It seems that in Compat_Make, when foo.o is tagged OP_MADE, this
only prevents the sources of foo.o from being made, not foo.o itself,
which is why we reach Compat_Make trying to make foo.c and crashing.
Or something. It's not clear to me if this is correct or not, but it's
consistent with the documentation for the .MADE tag.
 
It is not at all clear to me how to fix this properly. Obviously we
can avoid the crash in various ways, and maybe that should be done as
a bandaid, but some piece of the above logic needs to be amended as
well.

>How-To-Repeat:

   --- snip ---
.SUFFIXES:
.SUFFIXES: .c .o

.c.o:
        echo boo

all: lib.a

lib.a: lib.a(foo.o)
        echo aaa
foo.o: foo.c
        echo ccc
   --- snip ---

>Fix:

Please discuss.



Home | Main Index | Thread Index | Old Index