[LLVMbugs] [Bug 13442] New: ReadDataFromGlobal bad read on unaligned array access

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Mon Jul 23 15:15:56 PDT 2012


http://llvm.org/bugs/show_bug.cgi?id=13442

             Bug #: 13442
           Summary: ReadDataFromGlobal bad read on unaligned array access
           Product: libraries
           Version: trunk
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: Scalar Optimizations
        AssignedTo: unassignedbugs at nondot.org
        ReportedBy: cs448 at cam.ac.uk
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified


The following sample program:

#include <stdint.h>
#include <stdio.h>

const int test[4] = {1, 2, 3, 4};

int main(int argc, char** argv) {

  uint64_t r = *((uint64_t*)(((char*)test) + 2));
  printf("Result: %lx\n", r);
  return 0;

}

Compiled with gcc:

$ gcc test.c -O2 -o test
$ ./test
Result: 3000000020000

As you'd expect, it reads the low byte of the second and third array elements.

Compiled with Dragonegg (I'm using GCC 4.5 and LLVM 2.8, but the underlying
mistake is still present in trunk):

$ /home/chris/gcc-4.5-build/install/bin/gcc
-fplugin=/home/chris/dragonegg-2.8/dragonegg.so -O2 test.c -o test-ll
$ ./test
Result: 200000000

The program is wrongly optimised.

As llvm, the offending defn and instruction are:

@test = constant %"int[]" [i32 1, i32 2, i32 3, i32 4], align 16

%0 = load i64* bitcast (i8* getelementptr (i8* bitcast (%"int[]"* @test to
i8*), i64 2) to i64*), align 8

The cause of the bad optimisation is a call from Transforms/SCCP via
ConstantFoldLoadFromConstPtr (in Analysis/ConstantFolding.cpp) to
ReadDataFromGlobal: this handles a constant array using:

  if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) {
    uint64_t EltSize = TD.getTypeAllocSize(CA->getType()->getElementType());
    uint64_t Index = ByteOffset / EltSize;
    uint64_t Offset = ByteOffset - Index * EltSize;
    for (; Index != CA->getType()->getNumElements(); ++Index) {
      if (!ReadDataFromGlobal(CA->getOperand(Index), Offset, CurPtr,
                              BytesLeft, TD))
        return false;
      if (EltSize >= BytesLeft)
        return true;

      Offset = 0;      
      BytesLeft -= EltSize;
      CurPtr += EltSize;

    }
    return true;
  }

BytesLeft and CurPtr are both bumped by EltSize even if Offset was non-zero,
the recursive call will have read less than a full element. As a result we read
2 bytes from element 0 of the array, skip 2 uninitialised bytes by incrementing
the pointer by sizeof(int) == 4, then read the full next element. Good luck on
our part means the uninit bytes were 0 and so we get 0x200000000 with the 0x03
byte missing.

The patch is simple:

      Offset = 0;      
      BytesLeft -= EltSize;
      CurPtr += EltSize;

Should be

      BytesLeft -= (EltSize - Offset);
      CurPtr += (EltSize - Offset);
      Offset = 0;

-- 
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.



More information about the llvm-bugs mailing list