Package: make
Version: 3.81-8.2
Severity: grave
Justification: renders package unusable
Control: block 725629 with -1

Hi,

consider this Makefile:

----- Makefile/Makefile.in -----
all:
        do_something
foo:
        echo '# foo' > $@
Makefile: Makefile.in foo
        cat Makfile.in foo > $@
----- -----

If 'foo' does not exist, any execution of the 'all' target should first
create 'foo' and recreate 'Makefile'. This works fine, unless foo is
created with the same timestamp as the existing Makefile.

Attached is a slightly more advanced proof-of-concept Makefile.in, run
it as 

  time make -f Makefile.in loop

It should run forever, but on all machines where I tried it, it
terminated after some time because Makefile was not updated:

$ time make -f Makefile.in loop
make clean
make[1]: Entering directory '/home/andreas/725629'
rm -f blah
cp Makefile.in Makefile
make[1]: Leaving directory '/home/andreas/725629'
set -x ; while make test ; do make clean ; done
+ make test
make[1]: Entering directory '/home/andreas/725629'
echo 'foobar:' >blah
echo '  @echo FOOBAR' >>blah
cat Makefile.in blah > Makefile
if ! grep -q ^foobar: Makefile ; then echo FAIL ; ls -lart 
--time-style=full-iso Makefile* blah ; exit 1 ; else echo OK ; fi
OK
make[1]: Leaving directory '/home/andreas/725629'
+ make clean
make[1]: Entering directory '/home/andreas/725629'
rm -f blah
cp Makefile.in Makefile
make[1]: Leaving directory '/home/andreas/725629'
[... skipped some iterations ...]
+ make test
make[1]: Entering directory '/home/andreas/725629'
echo 'foobar:' >blah
echo '  @echo FOOBAR' >>blah
cat Makefile.in blah > Makefile
if ! grep -q ^foobar: Makefile ; then echo FAIL ; ls -lart 
--time-style=full-iso Makefile* blah ; exit 1 ; else echo OK ; fi
OK
make[1]: Leaving directory '/home/andreas/725629'
+ make clean
make[1]: Entering directory '/home/andreas/725629'
rm -f blah
cp Makefile.in Makefile
make[1]: Leaving directory '/home/andreas/725629'
+ make test
make[1]: Entering directory '/home/andreas/725629'
echo 'foobar:' >blah
echo '  @echo FOOBAR' >>blah
if ! grep -q ^foobar: Makefile ; then echo FAIL ; ls -lart 
--time-style=full-iso Makefile* blah ; exit 1 ; else echo OK ; fi
FAIL
-rw-r--r-- 1 andreas andreas 377 2016-04-11 03:03:37.588201637 +0200 Makefile.in
-rw-r--r-- 1 andreas andreas  22 2016-04-11 03:40:50.757214074 +0200 blah
-rw-r--r-- 1 andreas andreas 377 2016-04-11 03:40:50.757214074 +0200 Makefile
Makefile:2: recipe for target 'test' failed
make[1]: *** [test] Error 1
make[1]: Leaving directory '/home/andreas/725629'

real    0m0.152s
user    0m0.012s
sys     0m0.016s

It terminates even faster on a filesystem with one-second-resolution:

anbe@exodar:~/725629$ time make -f Makefile.in loop
make clean
make[1]: Entering directory '/home/anbe/725629'
rm -f blah
cp Makefile.in Makefile
make[1]: Leaving directory '/home/anbe/725629'
set -x ; while make test ; do make clean ; done
+ make test
make[1]: Entering directory '/home/anbe/725629'
echo 'foobar:' >blah
echo '  @echo FOOBAR' >>blah
if ! grep -q ^foobar: Makefile ; then echo FAIL ; ls -lart 
--time-style=full-iso Makefile* blah ; exit 1 ; else echo OK ; fi
FAIL
-rw-r--r-- 1 anbe anbe 266 2016-04-11 02:45:46.000000000 +0200 Makefile.in.old
-rw-r--r-- 1 anbe anbe 377 2016-04-11 03:08:04.000000000 +0200 Makefile.in
-rw-r--r-- 1 anbe anbe  22 2016-04-11 03:09:25.000000000 +0200 blah
-rw-r--r-- 1 anbe anbe 377 2016-04-11 03:09:25.000000000 +0200 Makefile
Makefile:2: recipe for target 'test' failed
make[1]: *** [test] Error 1
make[1]: Leaving directory '/home/anbe/725629'

real    0m0.080s
user    0m0.000s
sys     0m0.000s


I could reproduce this on different architectures, with different
filesystems (ppc64el/ext4, hurd-i386/ext2 amd64/xfs,tmpfs) and with
the make packages from wheezy, jessie and stretch.

An example where this bug (non-deterministically) breaks the build process
on some architectures, is #725629.

Andreas
test: Makefile
        if ! grep -q ^foobar: Makefile ; then echo FAIL ; ls -lart 
--time-style=full-iso Makefile* blah ; exit 1 ; else echo OK ; fi

Makefile: Makefile.in blah
        cat Makefile.in blah > $@

blah:   
        echo 'foobar:' >$@
        echo '  @echo FOOBAR' >>$@

clean:  
        rm -f blah
        cp Makefile.in Makefile

loop: Makefile
        make clean
        set -x ; while make test ; do make clean ; done

Reply via email to