Ramkumar Ramachandra
2014-Dec-22 01:11 UTC
[LLVMdev] [BUG x2] getPointerToGlobal is broken
Hi, Yes, I know getPointerToGlobal is deprecated, but it's the only interface we have in the OCaml world. So this is an investigation to see if the newer interfaces, specifically getGlobalValueAddress, suffers from the same problems. The first bug is fun; if you have emit two anonymous functions, and pass gptg their function objects to get the value via Ctypes, the second gtpg grabs the value of the first function: diff --git a/test/Bindings/OCaml/executionengine.ml b/test/Bindings/OCaml/executionengine.ml index 893f988..6e4a5ad 100644 --- a/test/Bindings/OCaml/executionengine.ml +++ b/test/Bindings/OCaml/executionengine.ml @@ -42,6 +42,22 @@ let define_plus m ignore (build_ret add b); fn +let define_anon1 m + let fn = define_function "" (function_type i32_type [| i32_type; + i32_type |]) m in + let b = builder_at_end (global_context ()) (entry_block fn) in + let add = build_add (param fn 0) (param fn 1) "sum" b in + ignore (build_ret add b); + fn + +let define_anon2 m + let fn = define_function "" (function_type i32_type [| i32_type; + i32_type |]) m in + let b = builder_at_end (global_context ()) (entry_block fn) in + let add = build_sub (param fn 0) (param fn 1) "diff" b in + ignore (build_ret add b); + fn + let test_executionengine () let open Ctypes in @@ -51,6 +67,8 @@ let test_executionengine () (* add plus *) let plus = define_plus m in + let anon1 = define_anon1 m in + let anon2 = define_anon2 m in (* add module *) let m2 = create_module (global_context ()) "test_module2" in @@ -78,6 +96,13 @@ let test_executionengine () let cplus = get_pointer_to_global plus cplusty ee in if 4l <> cplus 2l 2l then bomb "plus didn't work"; + (* call anon1 and anon2 *) + let canonty = Foreign.funptr (int32_t @-> int32_t @-> returning int32_t) in + let canon1 = get_pointer_to_global anon1 canonty ee in + let canon2 = get_pointer_to_global anon2 canonty ee in + if 4l <> canon1 2l 2l then bomb "anon1 didn't work"; + if 0l <> canon2 2l 2l then bomb "anon2 didn't work"; + (* call getglobal *) (* let cgetglobalty = Foreign.funptr (void @-> returning int32_t) in let cgetglobal = get_pointer_to_global getglobal cgetglobalty ee in anon2 reports the same value as anon1. Since ggva clearly asks for a string identifier, this confusion doesn't apply to it. Nevertheless, it should be noted that it's impossible to grab two anonymous functions uniquely via this interface. I'm still working on uncovering the details of this next bug; gtpg cannot be interspersed with define_function statements; a SIGSEGV results otherwise: diff --git a/test/Bindings/OCaml/executionengine.ml b/test/Bindings/OCaml/executionengine.ml index 893f988..a4c8123 100644 --- a/test/Bindings/OCaml/executionengine.ml +++ b/test/Bindings/OCaml/executionengine.ml @@ -42,6 +42,22 @@ let define_plus m ignore (build_ret add b); fn +let define_ooo1 m + let fn = define_function "ooo1" (function_type i32_type [| i32_type; + i32_type |]) m in + let b = builder_at_end (global_context ()) (entry_block fn) in + let add = build_add (param fn 0) (param fn 1) "sum" b in + ignore (build_ret add b); + fn + +let define_ooo2 m + let fn = define_function "ooo2" (function_type i32_type [| i32_type; + i32_type |]) m in + let b = builder_at_end (global_context ()) (entry_block fn) in + let add = build_sub (param fn 0) (param fn 1) "diff" b in + ignore (build_ret add b); + fn + let test_executionengine () let open Ctypes in @@ -78,6 +94,14 @@ let test_executionengine () let cplus = get_pointer_to_global plus cplusty ee in if 4l <> cplus 2l 2l then bomb "plus didn't work"; + (* define and execute out of order *) + let ooo1 = define_ooo1 m in + let cooo1 = get_pointer_to_global ooo1 cplusty ee in + if 4l <> cooo1 2l 2l then bomb "anon1 didn't work"; + let ooo2 = define_ooo2 m in + let cooo2 = get_pointer_to_global ooo2 cplusty ee in + if 0l <> cooo2 2l 2l then bomb "anon2 didn't work"; + (* call getglobal *) (* let cgetglobalty = Foreign.funptr (void @-> returning int32_t) in let cgetglobal = get_pointer_to_global getglobal cgetglobalty ee in I'll try to reproduce this with ggva using the C++ API so that it's clearer. Thanks. Ram
Ramkumar Ramachandra
2014-Dec-22 01:45 UTC
[LLVMdev] [BUG x2] getPointerToGlobal is broken
Never mind; I'm just rediscovering bugs, it seems. From unittests/ExecutionEngine/MCJIT/MCJITTest.cpp: // FIXME: This case fails due to a bug with getPointerToGlobal(). // The bug is due to MCJIT not having an implementation of getPointerToGlobal() // which results in falling back on the ExecutionEngine implementation that // allocates a new memory block for the global instead of using the same // global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below) // has the correct initial value, but updates to the real global (accessed by // JITted code) are not propagated. Instead, getPointerToGlobal() should return // a pointer into the loaded ObjectImage to reference the emitted global. The OCaml bindings need to chuck gptg and replace it with a wrapper to a more suitable function.