Bug 2230598 - compiler bug on aarm64: Memory allocation failure in xrealloc
Summary: compiler bug on aarm64: Memory allocation failure in xrealloc
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 9
Classification: Red Hat
Component: gcc
Version: 9.2
Hardware: aarch64
OS: Linux
medium
medium
Target Milestone: rc
: ---
Assignee: Marek Polacek
QA Contact: qe-baseos-tools-bugs
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2023-08-09 17:13 UTC by Paulo Andrade
Modified: 2023-08-09 19:35 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-08-09 19:17:58 UTC
Type: Bug
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)
simple.c (928 bytes, text/plain)
2023-08-09 17:13 UTC, Paulo Andrade
no flags Details
simple.f (360 bytes, text/plain)
2023-08-09 17:14 UTC, Paulo Andrade
no flags Details


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker RHELPLAN-165190 0 None None None 2023-08-09 17:13:52 UTC

Description Paulo Andrade 2023-08-09 17:13:27 UTC
Created attachment 1982609 [details]
simple.c

Reproducer:

$ gcc -c simple.c
$ gfortran -g -O0 simple.f -o simple simple.o
$ ./simple
Operating system error: Cannot allocate memory
Memory allocation failure in xrealloc

Several minor changes to simple.c workaround the problem, but should be
just hiding the problem.

$ rpm -q gcc libgfortran
gcc-11.3.1-4.3.el9.aarch64
libgfortran-11.3.1-4.3.el9.aarch64

...
Catchpoint 2 (call to syscall mmap), __GI___mmap64 (offset=0, fd=-1, flags=34, prot=3, len=281470681747456, addr=0x0)
    at ../sysdeps/unix/sysv/linux/mmap64.c:59
59	  return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd, offset);
(gdb) bt full
#0  __GI___mmap64 (offset=0, fd=-1, flags=34, prot=3, len=281470681747456, addr=0x0) at ../sysdeps/unix/sysv/linux/mmap64.c:59
        sc_ret = 0
#1  __GI___mmap64 (addr=addr@entry=0x0, len=len@entry=281470681747456, prot=3, flags=flags@entry=34, fd=fd@entry=-1, offset=offset@entry=0)
    at ../sysdeps/unix/sysv/linux/mmap64.c:47
        sc_ret = <optimized out>
        _sys_result = <optimized out>
        _x5tmp = <optimized out>
        _x4tmp = <optimized out>
        _x3tmp = <optimized out>
        _x2tmp = <optimized out>
        _x1tmp = <optimized out>
        _x0tmp = <optimized out>
        _x0 = <optimized out>
        _x1 = <optimized out>
        _x2 = <optimized out>
        _x3 = <optimized out>
        _x4 = <optimized out>
        _x5 = <optimized out>
        _x8 = <optimized out>
#2  0x0000fffff7c4e16c in sysmalloc (nb=nb@entry=281470681743888, av=av@entry=0xfffff7d5daf8 <main_arena>) at malloc.c:2424
        mm = <optimized out>
        old_top = <optimized out>
        old_size = <optimized out>
        old_end = <optimized out>
        size = 281470681747456
        brk = <optimized out>
        correction = <optimized out>
        snd_brk = <optimized out>
        front_misalign = <optimized out>
        end_misalign = <optimized out>
        aligned_brk = <optimized out>
        p = <optimized out>
        remainder = <optimized out>
        remainder_size = <optimized out>
        pagesize = 4096
        tried_mmap = true
        __PRETTY_FUNCTION__ = "sysmalloc"
#3  0x0000fffff7c4efa0 in _int_malloc (av=av@entry=0xfffff7d5daf8 <main_arena>, bytes=bytes@entry=281470681743873) at malloc.c:4274
        p = <optimized out>
        iters = <optimized out>
        nb = 281470681743888
        idx = 127
        bin = <optimized out>
        victim = <optimized out>
        size = <optimized out>
        victim_index = <optimized out>
        remainder = <optimized out>
        remainder_size = <optimized out>
        block = <optimized out>
        bit = <optimized out>
        map = <optimized out>
        fwd = <optimized out>
        bck = <optimized out>
        tcache_unsorted_count = 0
        tcache_nb = <optimized out>
        tc_idx = 17591917608991
        return_cached = <optimized out>
        __PRETTY_FUNCTION__ = "_int_malloc"
#4  0x0000fffff7c4f344 in _int_realloc (av=0xfffff7d5daf8 <main_arena>, oldp=0x421c20, oldsize=528, nb=281470681743888) at malloc.c:4745
        newp = <optimized out>
        newsize = <optimized out>
        newmem = <optimized out>
        next = 0x421e30
        remainder = <optimized out>
        remainder_size = <optimized out>
        __PRETTY_FUNCTION__ = "_int_realloc"
        nextsize = <optimized out>
#5  0x0000fffff7c506e4 in __GI___libc_realloc (oldmem=0x421c30, bytes=281470681743872) at malloc.c:3352
        ar_ptr = 0xfffff7d5daf8 <main_arena>
        nb = 281470681743888
        newp = <optimized out>
        oldp = 0x421c20
        oldsize = 528
        __PRETTY_FUNCTION__ = "__libc_realloc"
#6  0x0000fffff7e592e4 in _gfortrani_xrealloc (ptr=<optimized out>, size=size@entry=281470681743872) at ../../../libgfortran/runtime/memory.c:92
        newp = <optimized out>
#7  0x0000fffff7f57c5c in _gfortrani_fbuf_alloc (u=0x421870, len=281470681743366) at ../../../libgfortran/io/fbuf.c:123
        newlen = 281470681743872
        dest = <optimized out>
#8  0x0000fffff7f4a304 in _gfortrani_write_block (dtp=dtp@entry=0xffffffffea78, length=<optimized out>) at ../../../libgfortran/io/transfer.c:855
        dest = <optimized out>
#9  0x0000fffff7f525d8 in write_character (dtp=dtp@entry=0xffffffffea78, source=source@entry=0xffffffffecf0 "World!", kind=kind@entry=1, 
    length=length@entry=281470681743366, mode=mode@entry=1) at ../../../libgfortran/io/write.c:1416
        extra = <optimized out>
        p = <optimized out>
        d = <optimized out>
#10 0x0000fffff7f56b6c in list_formatted_write_scalar (dtp=dtp@entry=0xffffffffea78, type=type@entry=BT_CHARACTER, p=0xffffffffecf0, kind=kind@entry=1, 
    size=size@entry=281470681743366) at ../../../libgfortran/io/write.c:1900
No locals.
#11 0x0000fffff7f579e4 in _gfortrani_list_formatted_write (dtp=0xffffffffea78, type=BT_CHARACTER, p=<optimized out>, kind=1, size=281470681743366, nelems=1)
    at ../../../libgfortran/io/write.c:1972
        elem = 0
        tmp = <optimized out>
        stride = 281470681743366
#12 0x000000000040098c in simple (one=1, two=2, ts1=..., 
    ts2=<error reading variable: value requires 281470681743366 bytes, which is more than max-value-size>, three=3, four=4, five=5, _ts1=7, 
    _ts2=281470681743366) at simple.f:5
No locals.
#13 0x0000000000400c44 in main () at simple.c:27
        teststring1 = "Hello, \000P\355\377\377\377\377\000\000`\227\276\367\377\377\000", <incomplete sequence \310>
        teststring2 = "World!\000\000@\344\376\367\377\377", '\000' <repeats 18 times>, "\060\000\000\000\000\000\000\000\377\377\377\377\000\000\000\000\000"
        one = 1
        two = 2
        three = 3
        four = 4
        five = 5
        six = 6
        clen1 = <optimized out>
        clen2 = <optimized out>
        flen1 = 7
        flen2 = 6
        B3 = {clen = 1, flen = 65535, teststring = 0x0}
        B4 = {clen = 0, flen = 0, teststring = 0x2f8 <error: Cannot access memory at address 0x2f8>}
...

Comment 1 Paulo Andrade 2023-08-09 17:14:38 UTC
Created attachment 1982610 [details]
simple.f

Comment 2 Florian Weimer 2023-08-09 18:35:31 UTC
This really looks like a user error to me. With GCC 13 I get:

$ gfortran -Wall -O2 -flto simple.?
[…]
simple.c:26:15: warning: type of ‘simple_’ does not match original declaration [-Wlto-type-mismatch]
   26 |   extern void simple_(int* one, int* two, char* A, char *B, int* three, int* four, int* five, unsigned _A_len, unsigned _B_len);
      |               ^
simple.f:1:23: note: type mismatch in parameter 8
    1 |       SUBROUTINE SIMPLE(ONE,TWO,TS1,TS2,THREE,FOUR,FIVE)
      |                       ^
simple.f:1:23: note: type ‘long int’ should match type ‘unsigned int’
simple.f:1:23: note: ‘simple’ was previously declared here
simple.f:1:23: note: code may be misoptimized unless ‘-fno-strict-aliasing’ is used

Fixing simple.c as indicated to:

  extern void simple_(int* one, int* two, char* A, char *B, int* three, int* four, int* five, long _A_len, long _B_len);

This results in a working binary:

 FORTRAN Teststrings:Hello, World!
 FORTRAN Teststrings length:           7           6
           1           2           3           4           5

Comment 3 Paulo Andrade 2023-08-09 19:05:48 UTC
The problem is that the system compiler "works" with several minor changes,
like just commenting the line:

  fstring B3, B4;

in simple.c, or changing the types of fstring from unsigned int to unsigned
long, the warning from gcc 13 now, and several other tests, so, it might
be a genuine bug, as several minor changes the sources causes it work.

Comment 4 Jakub Jelinek 2023-08-09 19:17:58 UTC
As documented in https://gcc.gnu.org/gcc-8/changes.html#fortran , the Fortran ABI has changed in GCC 8.
In particular for this,
"Character variables longer than HUGE(0) elements are now possible on 64-bit targets. Note that this changes the procedure call ABI for all procedures with character arguments on 64-bit targets, as the type of the hidden character length argument has changed. The hidden character length argument is now of type INTEGER(C_SIZE_T)."
So, using unsigned for character lengths is incorrect on 64-bit architectures like aarch64.  On some architectures you can be lucky and have the upper 32 bits of the 64-bit argument zero and it will appear to "work", but that is clearly not the case here.

Comment 5 Florian Weimer 2023-08-09 19:23:18 UTC
For AArch64, the PCS says:

“
C.16 	If the size of the argument is less than 8 bytes then the size of the argument is set to 8 bytes. The effect is as if the argument was copied to the least significant bits of a 64-bit register and the remaining bits filled with unspecified values.
”

<https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#682parameter-passing-rules>

So it's indeed not expected to work, and you just get random uninitialized memory (which is why tiny changes make a difference).

Comment 6 Jakub Jelinek 2023-08-09 19:28:10 UTC
In particular, it was the https://gcc.gnu.org/PR78534 https://gcc.gnu.org/r8-5772 change.

Comment 7 Paulo Andrade 2023-08-09 19:35:42 UTC
(In reply to Jakub Jelinek from comment #4)
> As documented in https://gcc.gnu.org/gcc-8/changes.html#fortran , the
> Fortran ABI has changed in GCC 8.
> In particular for this,
> "Character variables longer than HUGE(0) elements are now possible on 64-bit
> targets. Note that this changes the procedure call ABI for all procedures
> with character arguments on 64-bit targets, as the type of the hidden
> character length argument has changed. The hidden character length argument
> is now of type INTEGER(C_SIZE_T)."
> So, using unsigned for character lengths is incorrect on 64-bit
> architectures like aarch64.  On some architectures you can be lucky and have
> the upper 32 bits of the 64-bit argument zero and it will appear to "work",
> but that is clearly not the case here.

Thanks. Heuristically this was a guess:
(gdb) p (int)281470681747456
$1 = 4096
and the linked document makes it clear.


Note You need to log in before you can comment on or make changes to this bug.