Failed LLVM Assertion with Constant Strings on Windows
Describe the Bug
On Windows 10 with LLVM 11.0.1, calling VectorType::get_size() causes the program to crash immediately. This is unexpected since the function's public API indicates it should be considered safe.
To Reproduce
Compile the following code using LLVM 11.0.1 on Windows 10:
use inkwell::context::Context;
fn main() {
let ctx = Context::create();
let const_string = ctx.const_string(b"test", true);
let const_type = const_string.get_type();
dbg!(const_type);
let size = const_type.get_size();
dbg!(size);
}
When executed this trips an exception during LLVM's cast routine when calling get_size which causes the final debug statement not to execute. Running the program yields the following trace:
[src\main.rs:7] const_type = VectorType {
vec_type: Type {
address: 0x000001f01b3ef420,
llvm_type: "[5 x i8]",
},
}
Assertion failed: isa<X>(Val) && "cast<Ty>() argument of incompatible type!", file C:\Users\john.rollinson\Code\LLVM11\llvm\include\llvm/Support/Casting.h, line 269
Expected Behavior Expect to run without any exceptions and produce the following trace (from Ubuntu 20.04 on WSL2):
[src/main.rs:7] const_type = VectorType {
vec_type: Type {
address: {{runtime specific memory address}},
llvm_type: "[5 x i8]",
},
}
[src/main.rs:9] size = 5
LLVM Version (please complete the following information):
- LLVM Version: 11.0.1 (compiled with clang-11)
- Inkwell Branch Used: llvm11-0
Desktop (please complete the following information):
- OS: Windows 10
Additional Context
I suspect the underlying problem may be an issue in LLVM itself given the behavior differences between Linux & Windows but started reporting it here since it is triggering an exception in "safe" Inkwell code. I have a workaround for the issue at the moment (compute the size via pure Rust) so am not digging too hard at the moment, but I will try to circle back and create an upstream issue on LLVM if I can determine the root cause.
On digging a little further, it looks like this is in fact a bug either in inkwell or possibly llvm-sys. Specifically, the following minimal C program which should be equivalent to the above Rust testcase succeeds in both Windows 10 and Ubuntu 20.04
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <llvm-c/Core.h>
int main(void) {
char *test_str = "https://github.com/TheDan64/inkwell/issues/248";
LLVMContextRef ctx = LLVMContextCreate();
LLVMValueRef llvm_str = LLVMConstStringInContext(ctx, test_str, strlen(test_str), false);
LLVMTypeRef str_type = LLVMTypeOf(llvm_str);
printf("typeof(llvm_str) = '%s'\n", LLVMPrintTypeToString(str_type));
unsigned size = LLVMGetVectorSize(str_type);
printf("len(test_str) = %u\n", size);
return 0;
}
(compiled with clang test.c `llvm-config-11 --cflags --ldflags --libs` )
This produces the expected results of
typeof(llvm_str) = '[47 x i8]'
len(test_str) = 47
I'll try to do another simple testcase with direct calls to llvm-sys next to see which interface is having the issues.
Is it because you provided null_terminated as true in your rust version, when it is actually not?
let const_string = ctx.const_string(b"test", true);
I suppose we could check for this automatically
I did some testing of what that option does and came to the conclusion that the semantics of that flag are confusing (not helped by llvm's naming of the parameter). The llvm parameter is DontNullTerminate which means passing false will add the null terminator. Since inkwell inverts the flag before calling to llvm-sys (which is a passthru implementation), passing true there actually tells llvm to add the null terminator (verified the functionality by digging into the LLVM IR and compiled object files).
Edit: That is to say - I think inkwell's flag would make more sense if instead of null_terminated it was null_terminate which would reflect what LLVM is actually asking/doing under the hood.
After some further digging, I discovered that I was accidentally linking the C code against a different version of LLVM than the Rust code (11.0.0 vs 11.0.1). When linked against the same version, the C code crashes as well so this looks like it is most likely an upstream issue. Once I get an issue created upstream I'll link to it here (their self-service account creation for bugzilla is disabled at the moment).