llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.58k stars 11.34k forks source link

Clang - Confusing crash in compiled program #81446

Open AldrinMathew opened 6 months ago

AldrinMathew commented 6 months ago

This seemingly correct LLVM IR is crashing once it is compiled and run using clang

The command for compilation throughout this example is clang -c --target=x86_64-unknown-linux-gnu ./test/file-m2.ll -o ./test/file-m2.o && clang -o ./test/m2 --target=x86_64-unknown-linux-gnu ./test/file-m2.o && ./test/m2

file-m2.txt

The specific suspicious part are lines 158 to 162:

%10 = call i32 (ptr, ...) @printf(ptr @"qat'str'101", i64 14, ptr @"qat'str'100")
%11 = load %"qat'type_Matrix:[4,2,qat'i32]", ptr %res, align 4
store %"qat'type_Matrix:[4,2,qat'i32]" zeroinitializer, ptr %res, align 4
store i32 0, ptr %i, align 4
ret %"qat'type_Matrix:[4,2,qat'i32]" %11

The strangest part is if that part is changed to the following, it no longer crashes:

%10 = load %"qat'type_Matrix:[4,2,qat'i32]", ptr %res, align 4
%11 = call i32 (ptr, ...) @printf(ptr @"qat'str'101", i64 14, ptr @"qat'str'100")
store %"qat'type_Matrix:[4,2,qat'i32]" zeroinitializer, ptr %res, align 4
store i32 0, ptr %i, align 4
ret %"qat'type_Matrix:[4,2,qat'i32]" %10

All I did here is reverse the order of the instructions %10 and %11

In the original program, the first order of instruction is the correct one. Similar for LLVM IR as well as these are not dependent on each other.

Similarly, if another instruction is added after %11 (in the original file), the program no longer crashes:

  %10 = call i32 (ptr, ...) @printf(ptr @"qat'str'101", i64 14, ptr @"qat'str'100")
  %11 = load %"qat'type_Matrix:[4,2,qat'i32]", ptr %res, align 4
  %"AnotherInst" = call i32 (ptr, ...) @printf(ptr @"qat'str'101", i64 14, ptr @"qat'str'100")
  store %"qat'type_Matrix:[4,2,qat'i32]" zeroinitializer, ptr %res, align 4
  store i32 0, ptr %i, align 4
  ret %"qat'type_Matrix:[4,2,qat'i32]" %11

I am not sure if this is an issue with clang or llvm.

AldrinMathew commented 6 months ago

Found something else. The original code presented is the logic for getting a transposed copy of a non-square matrix. If the original matrix is a square matrix, then the function doesn't crash. Here is the logic for a 3x3 matrix.

define %"qat'type_Matrix:[3,3,qat'i32]" @"qat'type_Matrix:[3,3,qat'i32]:method_get_transpose"(ptr %0) {
"0b":
  %"''" = alloca ptr, align 8
  %res = alloca %"qat'type_Matrix:[3,3,qat'i32]", align 8
  %i = alloca i32, align 4
  %j = alloca i32, align 4
  store ptr %0, ptr %"''", align 8
  %1 = load ptr, ptr %"''", align 8
  %2 = getelementptr inbounds %"qat'type_Matrix:[3,3,qat'i32]", ptr %1, i32 0, i32 0
  %3 = load [9 x i32], ptr %2, align 4
  call void @"qat'type_Matrix:[3,3,qat'i32]:convertor_from:[qat'array:[qat'i32,9]]"(ptr %res, [9 x i32] %3)
  store i32 0, ptr %i, align 4
  br label %"0b_0b"

"0b_0b":                                          ; preds = %"0b"
  %4 = load i32, ptr %i, align 4
  %5 = icmp ult i32 %4, 3
  br i1 %5, label %"0b_0b_0b", label %"1b"

"0b_0b_0b":                                       ; preds = %"0b_0b_1b", %"0b_0b"
  store i32 0, ptr %j, align 4
  br label %"0b_0b_0b_0b"

"0b_0b_1b":                                       ; preds = %"0b_0b_2b"
  %6 = load i32, ptr %i, align 4
  %7 = add i32 %6, 1
  store i32 %7, ptr %i, align 4
  %8 = load i32, ptr %i, align 4
  %9 = icmp ult i32 %8, 3
  br i1 %9, label %"0b_0b_0b", label %"1b"

"1b":                                             ; preds = %"0b_0b_1b", %"0b_0b"
  %10 = call i32 (ptr, ...) @printf(ptr @"qat'str'105", i64 14, ptr @"qat'str'104")
  %11 = load %"qat'type_Matrix:[3,3,qat'i32]", ptr %res, align 4
  store %"qat'type_Matrix:[3,3,qat'i32]" zeroinitializer, ptr %res, align 4
  store i32 0, ptr %i, align 4
  ret %"qat'type_Matrix:[3,3,qat'i32]" %11

"0b_0b_0b_0b":                                    ; preds = %"0b_0b_0b"
  %12 = load i32, ptr %j, align 4
  %13 = icmp ult i32 %12, 3
  br i1 %13, label %"0b_0b_0b_0b_0b", label %"0b_0b_2b"

"0b_0b_0b_0b_0b":                                 ; preds = %"0b_0b_0b_0b_1b", %"0b_0b_0b_0b"
  %14 = getelementptr inbounds %"qat'type_Matrix:[3,3,qat'i32]", ptr %res, i32 0, i32 0
  %15 = load i32, ptr %j, align 4
  %16 = mul i32 %15, 3
  %17 = load i32, ptr %i, align 4
  %18 = add i32 %16, %17
  %19 = getelementptr inbounds [9 x i32], ptr %14, i64 0, i32 %18
  %20 = getelementptr inbounds %"qat'type_Matrix:[3,3,qat'i32]", ptr %1, i32 0, i32 0
  %21 = load i32, ptr %i, align 4
  %22 = mul i32 %21, 3
  %23 = load i32, ptr %j, align 4
  %24 = add i32 %22, %23
  %25 = getelementptr inbounds [9 x i32], ptr %20, i64 0, i32 %24
  %26 = load i32, ptr %25, align 4
  store i32 %26, ptr %19, align 4
  br label %"0b_0b_0b_0b_1b"

"0b_0b_0b_0b_1b":                                 ; preds = %"0b_0b_0b_0b_0b"
  %27 = load i32, ptr %j, align 4
  %28 = add i32 %27, 1
  store i32 %28, ptr %j, align 4
  %29 = load i32, ptr %j, align 4
  %30 = icmp ult i32 %29, 3
  br i1 %30, label %"0b_0b_0b_0b_0b", label %"0b_0b_2b"

"0b_0b_2b":                                       ; preds = %"0b_0b_0b_0b_1b", %"0b_0b_0b_0b"
  store i32 0, ptr %j, align 4
  br label %"0b_0b_1b"
}
AldrinMathew commented 6 months ago

The obvious assumption is that this is a logical issue with the frontend and code in question, but then the initial example still doesn't make sense. Why does it crash in the first place, why does it stop crashing after adding an unrelated instruction in the middle?