Hello.

Thank you for reporting the issue.

The attached patch should fix the problem. It may be a bit of an
overkill, perhaps just one of the fixes would suffice, but it seems to
work at least.

I've re-made your useful script into an Automake test. Since
non-deterministic defects may be hard to find and fix, and certainly
harder to test if they're fixed, the new version simply runs parallel
'make recheck' a few times "just in case". Without the fix, the test
failed in the first or the second run. With the fix, the test (which
runs 'make recheck' 5 times) passed 5 times in a row. This *should* be
a decent sample.

All tests with "check" in the name pass.

The test and my patch can, of course, be adapted and further changed.

--
Regards - Bogdan ('bogdro') D.                 (GNU/Linux & FreeDOS)
X86 assembly (DOS, GNU/Linux):    http://bogdro.evai.pl/index-en.php
Soft(EN): http://bogdro.evai.pl/soft  http://bogdro.evai.pl/soft4asm
www.Xiph.org  www.TorProject.org  www.LibreOffice.org  www.GnuPG.org
From eb64fc56f13955a0b05b89492f48df886311191f Mon Sep 17 00:00:00 2001
From: Bogdan Drozdowski <>
Date: Sat, 17 Aug 2024 00:17:35 +0200
Subject: [PATCH] Bug#68860 Fix race condition in recheck

---
 bin/automake.in    |   6 +-
 lib/am/check.am    |   2 +-
 t/list-of-tests.mk |   1 +
 t/recheck-race.sh  | 135 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 3 deletions(-)
 create mode 100644 t/recheck-race.sh

diff --git a/bin/automake.in b/bin/automake.in
index a17f45236..1d6c29d1c 100644
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -4705,12 +4705,14 @@ sub do_check_merge_target ()
   # The check target must depend on the local equivalent of
   # 'all', to ensure all the primary targets are built.  Then it
   # must build the local check rules.
-  $output_rules .= "check-am: all-am\n";
+  $output_rules .= "check-am: all-am";
   if (@check)
     {
-      pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t  ", @check);
+      $output_rules .= " @check";
+      #pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t  ", @check);
       depend ('.MAKE', 'check-am');
     }
+  $output_rules .= "\n";
 
   if (@check_tests)
     {
diff --git a/lib/am/check.am b/lib/am/check.am
index e51a771bf..72c71a0f4 100644
--- a/lib/am/check.am
+++ b/lib/am/check.am
@@ -480,7 +480,7 @@ check-TESTS: %CHECK_DEPS%
 
 ## Recheck must depend on $(check_SCRIPTS), $(check_PROGRAMS), etc.
 ## It must also depend on the 'all' target.  See automake bug#11252.
-recheck: all %CHECK_DEPS%
+recheck: all-am %CHECK_DEPS%
 ## See comments above in the check-TESTS recipe for why remove
 ## $(TEST_SUITE_LOG) here.
 	@$(am__rm_f) $(TEST_SUITE_LOG)
diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk
index e80ace470..f359ba8a1 100644
--- a/t/list-of-tests.mk
+++ b/t/list-of-tests.mk
@@ -824,6 +824,7 @@ t/parallel-tests-no-spurious-summary.sh \
 t/parallel-tests-exit-statuses.sh \
 t/parallel-tests-console-output.sh \
 t/parallel-tests-once.sh \
+t/recheck-race.sh \
 t/tests-environment.sh \
 t/am-tests-environment.sh \
 t/tests-environment-backcompat.sh \
diff --git a/t/recheck-race.sh b/t/recheck-race.sh
new file mode 100644
index 000000000..abeb8c441
--- /dev/null
+++ b/t/recheck-race.sh
@@ -0,0 +1,135 @@
+#! /bin/sh
+# Copyright (C) 2024 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+# Test for race conditions in 'make recheck'.
+
+. test-init.sh
+
+cat > configure.ac <<EOF
+AC_INIT([foo], [2])
+AC_CONFIG_SRCDIR([config.h.in])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign silent-rules parallel-tests])
+AC_LANG([C++])
+AC_PROG_CXX
+AC_PROG_CXXCPP
+AC_PROG_RANLIB
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+EOF
+
+cat > Makefile.am <<EOF
+lib_LIBRARIES = libfoo.a
+libfoo_a_SOURCES = foo.cc
+
+check_LIBRARIES = libtest.a
+libtest_a_SOURCES = test.cc
+
+TESTS = one.test two.test
+TEST_EXTENSIONS = .test
+AM_DEFAULT_SOURCE_EXT = .cc
+EXTRA_PROGRAMS = \$(TESTS)
+
+libtest_a_LIBADD = libfoo.a
+LDADD = libtest.a libfoo.a
+EOF
+
+cat > foo.h <<EOF
+#ifndef my_foo_h
+#define my_foo_h
+#include <string>
+std::string foo(void);
+#endif
+EOF
+
+cat > foo.cc <<EOF
+#include <config.h>
+#include "foo.h"
+std::string foo(void) { return "fu"; }
+
+EOF
+
+cat > one.cc <<EOF
+#include <config.h>
+#include "foo.h"
+#include "test.h"
+#include <iostream>
+#include <string>
+int main(int argc, char* argv[])
+{
+	init(argc, argv);
+	std::cout << "Hello World!\n" << foo() << "\n";
+	return 0;
+}
+EOF
+
+cat > two.cc <<EOF
+#include <config.h>
+#include "foo.h"
+#include "test.h"
+#include <iostream>
+#include <string>
+int main(int argc, char* argv[])
+{
+	init(argc, argv);
+	std::string str = foo();
+	if (str != "foo") {
+	   std::cerr << "error: foo(): " << str << "\n";
+	   return 1;
+	}
+	return 0;
+}
+EOF
+
+cat > test.h <<EOF
+#ifndef my_test_h
+#define my_test_h
+void init(int argc, char* argv[]);
+#endif
+EOF
+
+cat > test.cc <<EOF
+#include <config.h>
+#include "test.h"
+#include "foo.h"
+#include <iostream>
+void init(int argc, char* argv[])
+{
+	std::cout << "init test for " << foo() << "\n";
+}
+EOF
+
+$ACLOCAL
+$AUTOCONF
+$AUTOHEADER
+$AUTOMAKE -a
+./configure --enable-silent-rules
+$MAKE all -j8
+run_make -M -e FAIL check -j8
+
+sed 's,"fu","foo",' < foo.cc > foo.cc-t && mv foo.cc-t foo.cc
+
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+
+:
-- 
2.35.1

Reply via email to