Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29277 Discussions

Program crashes caused by bug in free() from libc.so.6

mecej4
Honored Contributor III
1,051 Views

This is not an Intel compiler problem in itself, but I request users of Intel Fortran and Gfortran on Linux x64 systems to try the Fortran program below and reply with details (version of libc.so, compiler version, OS version) about their system if they see the bug on their system as well.

On certain Linux systems, the code for free() in libc.so.6 reads as follows:

000000000007e9f0 <__libc_free>:
...
   7e9ff:       48 85 ff                test   %rdi,%rdi
   7ea02:       74 6c                   je     7ea70 <__libc_free+0x80>
   7ea04:       48 8b 47 f8             mov    -0x8(%rdi),%rax
   7ea08:       48 8d 77 f0             lea    -0x10(%rdi),%rsi
...
   7ea1b:       48 89 f0                mov    %rsi,%rax
   7ea1e:       48 25 00 00 00 fc       and    $0xfffffffffc000000,%rax
   7ea24:       48 8b 38                mov    (%rax),%rdi            <<<==== crash if %rax =  0

A consequence is that if the address passed to free() as the base of the memory to free has bits 26 and up all unset (i.e., =zero), absolute address zero is going to be read from in the last instruction shown above, and the program will either crash or a trap will be taken.

Here is a Fortran program to expose the bug (please comment out the line with STOP to make the program actually crash).

program test_free_bug

   implicit none
   real, dimension (:), allocatable :: w
   integer :: dim, err, mskadr
   integer*8 :: locw    ! for 64 bit systems; INTEGER will do on 32-bit
  
   dim = 100
   print *, "Dimension of the array", dim
        
   allocate(w(dim), stat=err)
   if (err /= 0) print *, "w: allocation request denied"
      
   locw = LOC(w)
   write(*,'(A,Z16.16)')'Address of w after allocation = 0X',locw
        
   mskadr=IAND(locw,Z'FC000000')
   if(mskadr.eq.0)stop 'masked address is zero, will crash free() on Linux with libc.'

   if (allocated(w)) deallocate(w, stat=err)
   if (err /= 0) print *, "w: deallocation request denied"
  
end program test_free_bug

This bug report is an outcome of a recent thread in this forum, see https://software.intel.com/en-us/forums/topic/520165 .

0 Kudos
1 Reply
jimdempseyatthecove
Honored Contributor III
1,051 Views

One thing that comes to mind on some versions of Linux (32 bit) is user stack migrates down from 0xC0000000 and user text, followed by data begins at 0x08048000. If the heap were located in either of these two regions, then the assembly and instruction would never be 0 with a valid heap. Although this program is run on 64-bit, the bug may be that the 32-bit mask was erroneously used, and that most of the time, the code just happened to work.

Jim Dempsey

0 Kudos
Reply