jfecher / ante

A safe, easy systems language
http://antelang.org
MIT License
1.9k stars 80 forks source link

Incorrect Pointer Offset Calculation When Using -O3 Optimization Level #172

Closed eldesh closed 10 months ago

eldesh commented 10 months ago

When using -O3, there is a bug in the standard library's offset function that multiplies the required number by 8 erroneously. This behavior has been confirmed with the following sample code:

dbg_store (base: Ptr F64) ofs (value:F64) =
  addr = offset base ofs
  printne "addr: "
  printne (cast base: Usz)
  printne " + "
  printne ofs
  printne " -> "
  printne (cast addr : Usz)
  printne " "
  ptr_store addr value
  // array_insert base ofs value
  print (base#ofs)

main () =
  // allocate for 65536 floating point numbers
  arr: Ptr F64 = malloc (65536* size_of (MkType: Type F64))
  iter (Range 8447 65536) fn (i:Usz) ->
    dbg_store arr i (cast i)

  free arr

main ()

Output obtained on Ubuntu 22.04:

ante -O 3 -b main.an && ./main
addr: 140033084583952 + 8447 -> 140033085124560 8447.0
Segmentation fault

In this output, the address of the 8447th element is calculated by multiplying 8447 by 64 as an offset.

jfecher commented 10 months ago

Thanks for the report. Fixed in 13c7f08.

The issue was in the llvm backend on any optimization level. The Offset builtin calculated the correct type size for the offset, but llvm's GEP instruction also multiplied by the size of the result type for its offset. I've removed the extra manual type offset calculation for llvm and the code is working as expected now.

I'll also note that your code can be simplified a bit by making use of string interpolation:

dbg_store (base: Ptr F64) ofs (value:F64) =
  addr = offset base ofs
  printne "addr: ${cast base: Usz} + ${ofs} -> ${cast addr: Usz} "
  ptr_store addr value
  // array_insert base ofs value
  print (base#ofs)

main () =
  // allocate for 65536 floating point numbers
  arr: Ptr F64 = malloc (65536* size_of (MkType: Type F64))
  iter (Range 8447 65536) fn (i:Usz) ->
    dbg_store arr i (cast i)

  free arr

main ()