Compiling GNU Bison (HEAD~10) with the newest gnulib, and running "make check",
I get 8 test failures:
  testsuite: 608 615 619 620 622 623 625 626 failed
Seen on Ubuntu 22.04 and on Ubuntu 24.04 with gcc 13.

Same of the failures are caused by SIGSEGV, some by SIGABRT:

tests/testsuite.dir/608/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2359811 Aborted                 (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/615/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360097 Segmentation fault      (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/619/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360330 Aborted                 (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/620/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360350 Segmentation fault      (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/622/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360438 Aborted                 (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/623/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360460 Segmentation fault      (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/625/testsuite.log:+/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360610 Segmentation fault      (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}
tests/testsuite.dir/626/testsuite.log:/media/develdata/devel/BISON/bison-older/tests/bison:
 line 33: 2360667 Segmentation fault      (core dumped) $PREBISON 
"$abs_top_builddir/src/bison" ${1+"$@"}

I picked the first of these failures and ran it under valgrind:
  $ cd tests/testsuite.dir/608
  $ PREBISON=valgrind ./run
The first error shown by valgrind looks like this:

+==2376698== Invalid write of size 1
+==2376698==    at 0x4852EE3: memmove (in 
/usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
+==2376698==    by 0x48DCD87: memcpy (string_fortified.h:29)
+==2376698==    by 0x48DCD87: __printf_buffer_write (Xprintf_buffer_write.c:39)
+==2376698==    by 0x48E510B: __printf_buffer (vfprintf-internal.c:653)
+==2376698==    by 0x490BF65: __obstack_vprintf_internal (obprintf.c:95)
+==2376698==    by 0x490C0AB: obstack_printf (obprintf.c:120)
+==2376698==    by 0x138C70: prepare_symbol_definitions (output.c:624)
+==2376698==    by 0x13D40F: output (output.c:923)
+==2376698==    by 0x12E2B5: main (main.c:231)
+==2376698==  Address 0x4fa1fe0 is 10 bytes after a block of size 13,094 alloc'd
+==2376698==    at 0x4846828: malloc (in 
/usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
+==2376698==    by 0x188919: xmalloc (xmalloc.c:45)
+==2376698==    by 0x492B8BC: _obstack_newchunk (obstack.c:261)
+==2376698==    by 0x490BE7C: __printf_buffer_flush_obstack (obprintf.c:46)
+==2376698==    by 0x48DC78C: __printf_buffer_do_flush 
(printf_buffer_flush.c:77)
+==2376698==    by 0x48DC78C: __printf_buffer_flush (Xprintf_buffer_flush.c:65)
+==2376698==    by 0x48DC8D5: __printf_buffer_pad_1 (Xprintf_buffer_pad_1.c:33)
+==2376698==    by 0x48E693C: __printf_buffer_pad (printf_buffer.h:164)
+==2376698==    by 0x48E693C: __printf_buffer (vfprintf-process-arg.c:213)
+==2376698==    by 0x490BF65: __obstack_vprintf_internal (obprintf.c:95)
+==2376698==    by 0x490C0AB: obstack_printf (obprintf.c:120)
+==2376698==    by 0x1333FF: muscle_insert_int_table (output.c:100)
+==2376698==    by 0x13ADB4: prepare_actions (output.c:717)
+==2376698==    by 0x13D40A: output (output.c:922)

The cause is that this bison build uses the 'struct obstack' from gnulib
in combination with the obstack_printf function from glibc:

$ nm src/bison | grep obstack
0000000000007b22 t AnnotationList__alloc_on_obstack
0000000000065261 T bitset_obstack_alloc
0000000000065412 T bitset_obstack_free
00000000000b11c0 b format_obstack
00000000000b1ea0 b lbitset_obstack
00000000000b1ef8 b lbitset_obstack_init
00000000000b1140 B muscle_obstack
00000000000b0a80 D obstack_alloc_failed_handler
00000000000784b6 t _obstack_begin_worker
0000000000017095 t obstack_escape
00000000000263d4 t obstack_escape
000000000002ad94 t obstack_escape
00000000000465f1 t obstack_escape
00000000000b0358 D obstack_for_actions
00000000000b1520 b obstack_for_string
00000000000b16c0 b obstack_for_string
00000000000b1820 b obstack_for_string
00000000000b1240 B obstack_for_unquote
                 U obstack_printf@GLIBC_2.2.5
00000000000789ed T rpl_obstack_allocated_p
000000000007866d T rpl_obstack_begin
00000000000786c8 T rpl_obstack_begin_1
0000000000078a46 T rpl_obstack_free
0000000000078b06 T rpl_obstack_memory_used
0000000000078733 T rpl_obstack_newchunk
000000000000a5fe T Sbitset__new_on_obstack
00000000000b0cc0 b solved_conflicts_obstack
00000000000b0d20 b solved_conflicts_xml_obstack
00000000000b1da0 b tbitset_obstack
00000000000b1df8 b tbitset_obstack_init

At this point it's irrelevant whether this incompatibility is caused by
different layouts of 'struct obstack' or by different calling conventions
of _obstack_newchunk. The incompatibility needs to be avoided.

This patch does it, and it fixes all of the 8 test failures.


2025-07-12  Bruno Haible  <br...@clisp.org>

        obstack-printf: Fix memory overrun on glibc systems.
        * m4/obstack.m4 (gl_FUNC_OBSTACK): Define through AC_DEFUN_ONCE.
        * m4/obstack-printf.m4 (gl_FUNC_OBSTACK_PRINTF): Require
        gl_FUNC_OBSTACK. Invoke gl_REPLACE_OBSTACK_PRINTF when using the
        'obstack' replacement code.

diff --git a/m4/obstack-printf.m4 b/m4/obstack-printf.m4
index 05ca0af650..eeee458484 100644
--- a/m4/obstack-printf.m4
+++ b/m4/obstack-printf.m4
@@ -1,5 +1,5 @@
 # obstack-printf.m4
-# serial 4
+# serial 5
 dnl Copyright (C) 2008-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -12,12 +12,17 @@
 
 AC_DEFUN([gl_FUNC_OBSTACK_PRINTF],
 [
+  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_OBSTACK])
+
   dnl Persuade glibc <stdio.h> to declare obstack_printf(), obstack_vprintf().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   AC_CHECK_FUNCS_ONCE([obstack_printf])
-  if test $ac_cv_func_obstack_printf = no ; then
+  dnl The obstack_printf function from glibc does not work with the
+  dnl 'struct obstack' defined in gnulib's <obstack.h>.  Therefore, when
+  dnl overriding 'struct obstack', we must also override obstack_printf.
+  if test $HAVE_OBSTACK = 0 || test $REPLACE_OBSTACK = 1; then
     gl_REPLACE_OBSTACK_PRINTF
   fi
 
diff --git a/m4/obstack.m4 b/m4/obstack.m4
index 15f667332a..161370f86e 100644
--- a/m4/obstack.m4
+++ b/m4/obstack.m4
@@ -1,5 +1,5 @@
 # obstack.m4
-# serial 2
+# serial 3
 dnl Copyright 1996-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -11,7 +11,7 @@
 dnl Autoconf's AC_FUNC_OBSTACK is marked obsolete since version 2.70.
 dnl We provide our own macro here.
 
-AC_DEFUN([gl_FUNC_OBSTACK],
+AC_DEFUN_ONCE([gl_FUNC_OBSTACK],
 [
   AC_CHECK_HEADERS_ONCE([obstack.h])
   if test $ac_cv_header_obstack_h = yes; then




Reply via email to