Bug 114533 - libquadmath: printf: fix misaligned access on args
Summary: libquadmath: printf: fix misaligned access on args
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libquadmath (show other bugs)
Version: 13.2.1
: P3 normal
Target Milestone: 11.5
Assignee: Jakub Jelinek
URL:
Keywords: ABI
Depends on:
Blocks:
 
Reported: 2024-03-30 12:48 UTC by Matthias Klose
Modified: 2024-06-20 13:39 UTC (History)
5 users (show)

See Also:
Host:
Target: x86_64-linux-gnu
Build:
Known to work:
Known to fail: 11.4.1, 12.3.1, 13.2.1, 14.0
Last reconfirmed: 2024-04-02 00:00:00


Attachments
gcc14-pr114533.patch (488 bytes, patch)
2024-04-02 17:34 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2024-03-30 12:48:10 UTC
reported at
https://gcc.gnu.org/pipermail/gcc-patches/2024-March/647635.html

On x86, this compiles into movdqa which segfaults on unaligned access.

This kind of failure has been seen when running against glibc 2.39,
which incidentally changed the printf implementation to move away from
alloca() for this data to instead append it at the end of an existing
"scratch buffer", with arbitrary alignment, whereas alloca() was
probably more likely to be naturally aligned.

Tested by adding the patch to the Ubuntu gcc-14 package in
https://launchpad.net/~schopin/+archive/ubuntu/libquadmath

Signed-off-by: Simon Chopin <simon.chopin@canonical.com>
---
 libquadmath/printf/printf_fp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libquadmath/printf/printf_fp.c b/libquadmath/printf/printf_fp.c
index 8effcee88fa..d86aa650d38 100644
--- a/libquadmath/printf/printf_fp.c
+++ b/libquadmath/printf/printf_fp.c
@@ -363,7 +363,7 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp,
 
   /* Fetch the argument value.	*/
     {
-      fpnum = **(const __float128 **) args[0];
+      memcpy(&fpnum, *(void* const *) args[0], sizeof(fpnum));
 
       /* Check for special values: not a number or infinity.  */
       if (isnanq (fpnum))
Comment 1 Richard Biener 2024-04-02 11:29:48 UTC
The question is whether the caller misbehaves according to the ABI here?  There's likely a known alignment present we could re-instantiate with a
__builtin_assume_aligned?
Comment 2 Jakub Jelinek 2024-04-02 11:45:27 UTC
From what I can see, glibc uses there the same thing as libquadmath does, so why is it ok on the glibc side and not on the libquadmath side?

I mean
https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf_fp.c;h=e75706f089bba3baabbcfb6bcf41514bad0a9dcb;hb=HEAD#l222
and
https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf_fp.c;h=e75706f089bba3baabbcfb6bcf41514bad0a9dcb;hb=HEAD#l191
Comment 3 Andreas Schwab 2024-04-02 12:04:52 UTC
Is the stack properly aligned at this point?
Comment 4 Florian Weimer 2024-04-02 12:36:35 UTC
This looks like a glibc bug to me.
Comment 5 Andreas Schwab 2024-04-02 13:21:49 UTC
Without a test case it is hard to tell.
Comment 6 Andreas Schwab 2024-04-02 13:41:18 UTC
Looks like the issue is that args_pa_user is not kept aligned.  On the other hand, flt128_va already uses memcpy, so it does not expect the memory to be aligned.
Comment 7 Joseph S. Myers 2024-04-02 17:02:31 UTC
Note also that in glibc, _Float128 support in printf code can only be used in limited circumstances: either on powerpc64le, as one of the multiple supported long double formats there, or through the sharing of the printf code with the implementation of strfromf128.

In particular, there are no glibc printf formats corresponding directly to _FloatN / _FloatNx types. There was support in principle at the WG14 meeting in Strasbourg in January for having some form of printf/scanf support for such types in C2y, but major work is still needed on the wording that was proposed in N3184.
Comment 8 Jakub Jelinek 2024-04-02 17:08:34 UTC
I guess we should go with the above patch after fixing formatting, but it isn't enough,
printf_fphex.c has similar code.
Even in glibc which doesn't support printing _Float128 nor any other type which would require similar alignment, the hooks only register a function to fill in some mem and allows specification of size, but can't specify alignment.
Comment 9 Jerry DeLisle 2024-04-02 17:30:16 UTC
Adding myself here as I need hex format for gfortran EX format specifiers.
Comment 10 Jakub Jelinek 2024-04-02 17:34:54 UTC
Created attachment 57853 [details]
gcc14-pr114533.patch

Untested fix.  Unfortunately, we don't have any testsuite for libquadmath, hope it will be tested during libgfortran testing.
Comment 11 Matthias Klose 2024-04-02 18:26:09 UTC
while not a test case, that was seen when running autopkg tests of the evolver package against glibc 2.39 packages.

https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/2052929

the failing evolver test is:

echo "g 5; v; r ; g 10; v;" | evolver-nox-q cube
Comment 12 GCC Commits 2024-04-03 08:14:14 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:8455d6f6cd43b7b143ab9ee19437452fceba9cc9

commit r14-9769-g8455d6f6cd43b7b143ab9ee19437452fceba9cc9
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Apr 3 10:02:35 2024 +0200

    libquadmath: Don't assume the storage for __float128 arguments is aligned [PR114533]
    
    With the register_printf_type/register_printf_modifier/register_printf_specifier
    APIs the C library is just told the size of the argument and is provided with
    a callback to fetch the argument from va_list using va_arg into C library provided
    memory.  The C library isn't told what alignment requirement it has, but we were
    using direct load of a __float128 value from that memory which assumes
    __alignof (__float128) alignment.
    
    The following patch fixes that by using memcpy instead.
    
    I haven't been able to reproduce an actual crash, tried
     #include <quadmath.h>
     #include <stdlib.h>
     #include <stdio.h>
    
    int main ()
    {
      __float128 r;
      int prec = 20;
      int width = 46;
      char buf[128];
    
      r = 2.0q;
      r = sqrtq (r);
      int n = quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qe", width, r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: +1.41421356237309504880e+00 */
      quadmath_snprintf (buf, sizeof buf, "%Qa", r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: 0x1.6a09e667f3bcc908b2fb1366ea96p+0 */
      n = quadmath_snprintf (NULL, 0, "%+-#46.*Qe", prec, r);
      if (n > -1)
        {
          char *str = malloc (n + 1);
          if (str)
            {
              quadmath_snprintf (str, n + 1, "%+-#46.*Qe", prec, r);
              printf ("%s\n", str);
              /* Prints: +1.41421356237309504880e+00 */
            }
          free (str);
        }
      printf ("%+-#*.20Qe\n", width, r);
      printf ("%Qa\n", r);
      printf ("%+-#46.*Qe\n", prec, r);
      printf ("%d %Qe %d %Qe %d %Qe\n", 1, r, 2, r, 3, r);
      return 0;
    }
    In any case, I think memcpy for loading from it is right.
    
    2024-04-03  Simon Chopin  <simon.chopin@canonical.com>
                Jakub Jelinek  <jakub@redhat.com>
    
            PR libquadmath/114533
            * printf/printf_fp.c (__quadmath_printf_fp): Use memcpy to copy
            __float128 out of args.
            * printf/printf_fphex.c (__quadmath_printf_fphex): Likewise.
    
    Signed-off-by: Simon Chopin <simon.chopin@canonical.com>
Comment 13 GCC Commits 2024-04-21 04:08:43 UTC
The releases/gcc-13 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:cc39bd532d4de1ba0b2785246fb6fdd63ec2e92c

commit r13-8625-gcc39bd532d4de1ba0b2785246fb6fdd63ec2e92c
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Apr 3 10:02:35 2024 +0200

    libquadmath: Don't assume the storage for __float128 arguments is aligned [PR114533]
    
    With the register_printf_type/register_printf_modifier/register_printf_specifier
    APIs the C library is just told the size of the argument and is provided with
    a callback to fetch the argument from va_list using va_arg into C library provided
    memory.  The C library isn't told what alignment requirement it has, but we were
    using direct load of a __float128 value from that memory which assumes
    __alignof (__float128) alignment.
    
    The following patch fixes that by using memcpy instead.
    
    I haven't been able to reproduce an actual crash, tried
     #include <quadmath.h>
     #include <stdlib.h>
     #include <stdio.h>
    
    int main ()
    {
      __float128 r;
      int prec = 20;
      int width = 46;
      char buf[128];
    
      r = 2.0q;
      r = sqrtq (r);
      int n = quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qe", width, r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: +1.41421356237309504880e+00 */
      quadmath_snprintf (buf, sizeof buf, "%Qa", r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: 0x1.6a09e667f3bcc908b2fb1366ea96p+0 */
      n = quadmath_snprintf (NULL, 0, "%+-#46.*Qe", prec, r);
      if (n > -1)
        {
          char *str = malloc (n + 1);
          if (str)
            {
              quadmath_snprintf (str, n + 1, "%+-#46.*Qe", prec, r);
              printf ("%s\n", str);
              /* Prints: +1.41421356237309504880e+00 */
            }
          free (str);
        }
      printf ("%+-#*.20Qe\n", width, r);
      printf ("%Qa\n", r);
      printf ("%+-#46.*Qe\n", prec, r);
      printf ("%d %Qe %d %Qe %d %Qe\n", 1, r, 2, r, 3, r);
      return 0;
    }
    In any case, I think memcpy for loading from it is right.
    
    2024-04-03  Simon Chopin  <simon.chopin@canonical.com>
                Jakub Jelinek  <jakub@redhat.com>
    
            PR libquadmath/114533
            * printf/printf_fp.c (__quadmath_printf_fp): Use memcpy to copy
            __float128 out of args.
            * printf/printf_fphex.c (__quadmath_printf_fphex): Likewise.
    
    Signed-off-by: Simon Chopin <simon.chopin@canonical.com>
    (cherry picked from commit 8455d6f6cd43b7b143ab9ee19437452fceba9cc9)
Comment 14 Jakub Jelinek 2024-04-23 06:45:52 UTC
Fixed for 13.3 too.
Comment 15 GCC Commits 2024-06-11 10:37:39 UTC
The releases/gcc-12 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:9987fe67cf6211515d8ebf6528cc83c77dfb5bf3

commit r12-10517-g9987fe67cf6211515d8ebf6528cc83c77dfb5bf3
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Apr 3 10:02:35 2024 +0200

    libquadmath: Don't assume the storage for __float128 arguments is aligned [PR114533]
    
    With the register_printf_type/register_printf_modifier/register_printf_specifier
    APIs the C library is just told the size of the argument and is provided with
    a callback to fetch the argument from va_list using va_arg into C library provided
    memory.  The C library isn't told what alignment requirement it has, but we were
    using direct load of a __float128 value from that memory which assumes
    __alignof (__float128) alignment.
    
    The following patch fixes that by using memcpy instead.
    
    I haven't been able to reproduce an actual crash, tried
     #include <quadmath.h>
     #include <stdlib.h>
     #include <stdio.h>
    
    int main ()
    {
      __float128 r;
      int prec = 20;
      int width = 46;
      char buf[128];
    
      r = 2.0q;
      r = sqrtq (r);
      int n = quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qe", width, r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: +1.41421356237309504880e+00 */
      quadmath_snprintf (buf, sizeof buf, "%Qa", r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: 0x1.6a09e667f3bcc908b2fb1366ea96p+0 */
      n = quadmath_snprintf (NULL, 0, "%+-#46.*Qe", prec, r);
      if (n > -1)
        {
          char *str = malloc (n + 1);
          if (str)
            {
              quadmath_snprintf (str, n + 1, "%+-#46.*Qe", prec, r);
              printf ("%s\n", str);
              /* Prints: +1.41421356237309504880e+00 */
            }
          free (str);
        }
      printf ("%+-#*.20Qe\n", width, r);
      printf ("%Qa\n", r);
      printf ("%+-#46.*Qe\n", prec, r);
      printf ("%d %Qe %d %Qe %d %Qe\n", 1, r, 2, r, 3, r);
      return 0;
    }
    In any case, I think memcpy for loading from it is right.
    
    2024-04-03  Simon Chopin  <simon.chopin@canonical.com>
                Jakub Jelinek  <jakub@redhat.com>
    
            PR libquadmath/114533
            * printf/printf_fp.c (__quadmath_printf_fp): Use memcpy to copy
            __float128 out of args.
            * printf/printf_fphex.c (__quadmath_printf_fphex): Likewise.
    
    Signed-off-by: Simon Chopin <simon.chopin@canonical.com>
    (cherry picked from commit 8455d6f6cd43b7b143ab9ee19437452fceba9cc9)
Comment 16 Jakub Jelinek 2024-06-11 10:51:59 UTC
Should be fixed for 12.4+ too.
Comment 17 GCC Commits 2024-06-20 13:22:51 UTC
The releases/gcc-11 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:df41dbfd22528b1241668af21a979204b876fb67

commit r11-11500-gdf41dbfd22528b1241668af21a979204b876fb67
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Apr 3 10:02:35 2024 +0200

    libquadmath: Don't assume the storage for __float128 arguments is aligned [PR114533]
    
    With the register_printf_type/register_printf_modifier/register_printf_specifier
    APIs the C library is just told the size of the argument and is provided with
    a callback to fetch the argument from va_list using va_arg into C library provided
    memory.  The C library isn't told what alignment requirement it has, but we were
    using direct load of a __float128 value from that memory which assumes
    __alignof (__float128) alignment.
    
    The following patch fixes that by using memcpy instead.
    
    I haven't been able to reproduce an actual crash, tried
     #include <quadmath.h>
     #include <stdlib.h>
     #include <stdio.h>
    
    int main ()
    {
      __float128 r;
      int prec = 20;
      int width = 46;
      char buf[128];
    
      r = 2.0q;
      r = sqrtq (r);
      int n = quadmath_snprintf (buf, sizeof buf, "%+-#*.20Qe", width, r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: +1.41421356237309504880e+00 */
      quadmath_snprintf (buf, sizeof buf, "%Qa", r);
      if ((size_t) n < sizeof buf)
        printf ("%s\n", buf);
        /* Prints: 0x1.6a09e667f3bcc908b2fb1366ea96p+0 */
      n = quadmath_snprintf (NULL, 0, "%+-#46.*Qe", prec, r);
      if (n > -1)
        {
          char *str = malloc (n + 1);
          if (str)
            {
              quadmath_snprintf (str, n + 1, "%+-#46.*Qe", prec, r);
              printf ("%s\n", str);
              /* Prints: +1.41421356237309504880e+00 */
            }
          free (str);
        }
      printf ("%+-#*.20Qe\n", width, r);
      printf ("%Qa\n", r);
      printf ("%+-#46.*Qe\n", prec, r);
      printf ("%d %Qe %d %Qe %d %Qe\n", 1, r, 2, r, 3, r);
      return 0;
    }
    In any case, I think memcpy for loading from it is right.
    
    2024-04-03  Simon Chopin  <simon.chopin@canonical.com>
                Jakub Jelinek  <jakub@redhat.com>
    
            PR libquadmath/114533
            * printf/printf_fp.c (__quadmath_printf_fp): Use memcpy to copy
            __float128 out of args.
            * printf/printf_fphex.c (__quadmath_printf_fphex): Likewise.
    
    Signed-off-by: Simon Chopin <simon.chopin@canonical.com>
    (cherry picked from commit 8455d6f6cd43b7b143ab9ee19437452fceba9cc9)
Comment 18 Jakub Jelinek 2024-06-20 13:39:39 UTC
Fixed for 11.5 as well.