bug-texinfo
[Top][All Lists]
Advanced

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

Re: obstack module has alignment issues on sparc? (Re: set_labels_identi


From: Bruno Haible
Subject: Re: obstack module has alignment issues on sparc? (Re: set_labels_identifiers_target -fsanitize=undefined error)
Date: Tue, 14 Nov 2023 22:16:33 +0100

Sam James wrote:
> > It appears that the obstack gnulib module is the culprit.

I replied:
> Therefore, if it is a bug in gnulib, it is also a bug in glibc.

Sam was right. I was wrong. It is a bug in the 'obstack' gnulib module.

 The scope
 ---------

It is visible on CPUs that are
  - big-endian,
  - 64-bit,
  - not allowing unaligned accesses (this excludes powerpc64),
thus only on sparc64.

It is visible only on glibc systems. So, only on Linux/glibc/sparc64.

 The workaround
 --------------

Is attached.

 The explanation
 ---------------

The code in tree.c does not set the alignment explicitly; it uses the
DEFAULT_ALIGNMENT, which is 16. ('long', 'double', 'void *' all have
an __alignof__ of 8, and 'long double' has an __alignof__ of 16).

The code in tree.c is meant to use the code from gnulib's obstack.h
and obstack.c. obstack.c is compiled to libgnu_la-obstack.o, which is
then included in tp/Texinfo/XS/.libs/Parsetexi.so. Perl loads this
shared library via dlopen().

glibc and Parsetexi.so each define the obstack ABI symbols (_obstack_begin,
_obstack_begin_1, _obstack_newchunk, _obstack_free, etc.). Which of
the symbols "wins" at run time, depends on the flags passed to dlopen().
Apparently perl does not pass the RTLD_DEEPBIND flag. Therefore the
symbols from glibc take precedence. So, tree.c uses
  - the obstack.h *macros* from gnulib, but
  - the obstack *functions* from glibc.
The obstack facilities from gnulib and from glibc are nearly the same.
They use a 'struct obstack' with very similar layout. The only relevant
difference is that (on a 64-bit platform)

  - gnulib's struct obstack has a member

        unsigned long alignment_mask;

  - glibc's struct obstack instead has two members

        unsigned int alignment_mask;
        unsigned int __padding;

    (The padding is there because the next member is a pointer, which
    has alignment 8, see above.)

So, what happens is that during initialization of the obstack (variable
'obs_element' in tree.c) the glibc function _obstack_begin sets the
alignment_mask to DEFAULT_ALIGNMENT - 1, that is 0xf. The __padding member
is apparently 0.

Then, in the function alloc_element of tree.c, obstack_alloc - which is a
macro! - uses the gnulib struct layout and accesses the alignment_mask which
has a value 0xf00000000. __PTR_ALIGN with an alignment mask of 0xf00000000
does not change the bits 31..0 of the pointer. Since tree.c also contains
a call
  obstack_alloc (&obs_element, sizeof (int))
obstack_alloc returns a value that is ≡4 mod 8. tree.c then attempts to
access a pointer there, and this crashes with SIGBUS since it's not ≡0 mod 8.

 The root cause
 --------------

Gnulib generally uses idioms for overriding functions that are safe to use
in shared libraries and will avoid collisions. This is the business with
  REPLACE_FOO=1
and
  #define foo rpl_foo
and so on.

But the Gnulib module 'obstack' has never been updated to use these idioms.
It is still at the state of 1997 and uses a clunky _OBSTACK_INTERFACE_VERSION
mechanism.


Bruno

Attachment: obstack-fix.diff
Description: Text Data


reply via email to

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