From 3536605b230bb912ac97e2ad75a8373e1ea6dcbe Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Tue, 18 Oct 2022 02:07:19 +0800 Subject: [PATCH] Fix FFI specs on release builds (#12601) --- spec/compiler/data/ffi/sum.c | 53 +++++++++++++++------------- spec/compiler/ffi/ffi_spec.cr | 65 ++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 55 deletions(-) diff --git a/spec/compiler/data/ffi/sum.c b/spec/compiler/data/ffi/sum.c index 4d9f82717682..940830770d15 100644 --- a/spec/compiler/data/ffi/sum.c +++ b/spec/compiler/data/ffi/sum.c @@ -1,71 +1,76 @@ #include +#include #include "../visibility.h" -EXPORT int answer() +// all the integral return types must be at least as large as the register size +// to avoid integer promotion by FFI! + +EXPORT int64_t answer() { return 42; } -EXPORT int sum(int a, int b, int c) +EXPORT int64_t sum(int32_t a, int32_t b, int32_t c) { return a + b + c; } EXPORT void sum_primitive_types( - unsigned char a, signed char b, - unsigned short c, signed short d, - unsigned long e, signed long f, - unsigned long long g, signed long long h, + uint8_t a, int8_t b, + uint16_t c, int16_t d, + uint32_t e, int32_t f, + uint64_t g, int64_t h, float i, double j, - long *k) + int64_t *k) { - *k = a + b + c + d + e + f + g + h + (long)i + (long)j + *k; + *k = a + b + c + d + e + f + g + h + (int64_t)i + (int64_t)j + *k; } struct test_struct { - char b; - short s; - int i; - long long j; + int8_t b; + int16_t s; + int32_t i; + int64_t j; float f; double d; - int *p; + void *p; }; -EXPORT int sum_struct(struct test_struct s) +EXPORT int64_t sum_struct(struct test_struct s) { - *s.p = s.b + s.s + s.i + s.j + s.f + s.d + *(s.p); - return *s.p; + int64_t *p = (int64_t *)s.p; + *p = s.b + s.s + s.i + s.j + s.f + s.d + *p; + return *p; } -EXPORT int sum_array(int ary[4]) +EXPORT int64_t sum_array(int32_t ary[4]) { - int sum = 0; - for (int i = 0; i < 4; i++) + int64_t sum = 0; + for (int32_t i = 0; i < 4; i++) { sum += ary[i]; } return sum; } -EXPORT int sum_variadic(int count, ...) +EXPORT int64_t sum_variadic(int32_t count, ...) { va_list ap; - int j; - int sum = 0; + int32_t j; + int64_t sum = 0; va_start(ap, count); /* Requires the last fixed parameter (to get the address) */ for (j = 0; j < count; j++) { - sum += va_arg(ap, int); /* Increments ap to the next argument. */ + sum += va_arg(ap, int32_t); /* Increments ap to the next argument. */ } va_end(ap); return sum; } -EXPORT struct test_struct make_struct(char b, short s, int i, long long j, float f, double d, void *p) +EXPORT struct test_struct make_struct(int8_t b, int16_t s, int32_t i, int64_t j, float f, double d, void *p) { struct test_struct t; t.b = b; diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr index 5bf1b3cc97f2..ac16cfc425f2 100644 --- a/spec/compiler/ffi/ffi_spec.cr +++ b/spec/compiler/ffi/ffi_spec.cr @@ -6,14 +6,17 @@ require "compiler/crystal/ffi" require "compiler/crystal/loader" require "../loader/spec_helper" +# all the integral return types must be at least as large as the register size +# to avoid integer promotion by FFI! + @[Extern] private record TestStruct, - b : LibC::Char, - s : LibC::Short, - i : LibC::Int, - j : LibC::LongLong, - f : LibC::Float, - d : LibC::Double, + b : Int8, + s : Int16, + i : Int32, + j : Int64, + f : Float32, + d : Float64, p : Pointer(Void) describe Crystal::FFI::CallInterface do @@ -28,20 +31,20 @@ describe Crystal::FFI::CallInterface do describe ".new" do it "simple call" do - call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint16, [] of Crystal::FFI::Type + call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint64, [] of Crystal::FFI::Type loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH]) loader.load_library "sum" function_pointer = loader.find_symbol("answer") - return_value = 0_i32 + return_value = 0_i64 call_interface.call(function_pointer, Pointer(Pointer(Void)).null, pointerof(return_value).as(Void*)) - return_value.should eq 42 + return_value.should eq 42_i64 ensure loader.try &.close_all end it "with args" do - call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint16, [ + call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint64, [ Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, ] of Crystal::FFI::Type @@ -49,11 +52,11 @@ describe Crystal::FFI::CallInterface do loader.load_library "sum" function_pointer = loader.find_symbol("sum") - return_value = 0_i32 + return_value = 0_i64 args = Int32[1, 3, 5] arg_pointers = StaticArray(Pointer(Void), 3).new { |i| (args.to_unsafe + i).as(Void*) } call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) - return_value.should eq 9 + return_value.should eq 9_i64 ensure loader.try &.close_all end @@ -72,7 +75,7 @@ describe Crystal::FFI::CallInterface do loader.load_library "sum" function_pointer = loader.find_symbol("sum_primitive_types") - pointer_value = 11_i32 + pointer_value = 11_i64 arg_pointers = StaticArray[ Pointer(UInt8).malloc(1, 1).as(Void*), Pointer(Int8).malloc(1, 2).as(Void*), @@ -84,7 +87,7 @@ describe Crystal::FFI::CallInterface do Pointer(Int64).malloc(1, 8).as(Void*), Pointer(Float32).malloc(1, 9.0).as(Void*), Pointer(Float64).malloc(1, 10.0).as(Void*), - Pointer(Int32*).malloc(1, pointerof(pointer_value)).as(Void*), + Pointer(Int64*).malloc(1, pointerof(pointer_value)).as(Void*), Pointer(Void).null, ] @@ -130,7 +133,7 @@ describe Crystal::FFI::CallInterface do end it "sum struct" do - call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint32, [ + call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint64, [ Crystal::FFI::Type.struct([ Crystal::FFI::Type.sint8, Crystal::FFI::Type.sint16, @@ -146,7 +149,7 @@ describe Crystal::FFI::CallInterface do loader.load_library "sum" function_pointer = loader.find_symbol("sum_struct") - pointer_value = 11_i32 + pointer_value = 11_i64 arg_pointers = StaticArray[ Pointer(TestStruct).malloc(1, TestStruct.new( b: 2, @@ -160,10 +163,10 @@ describe Crystal::FFI::CallInterface do Pointer(Void).null, ] - return_value = 0i32 + return_value = 0_i64 call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) - return_value.should eq 50 - pointer_value.should eq 50 + return_value.should eq 50_i64 + pointer_value.should eq 50_i64 ensure loader.try &.close_all end @@ -171,7 +174,7 @@ describe Crystal::FFI::CallInterface do # passing C array by value is not supported everywhere {% unless flag?(:win32) %} it "array" do - call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint32, [ + call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint64, [ Crystal::FFI::Type.struct([ Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, @@ -184,7 +187,7 @@ describe Crystal::FFI::CallInterface do loader.load_library "sum" function_pointer = loader.find_symbol("sum_array") - return_value = 0_i32 + return_value = 0_i64 ary = [1, 2, 3, 4] @@ -194,7 +197,7 @@ describe Crystal::FFI::CallInterface do ] call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) - return_value.should eq 10 + return_value.should eq 10_i64 ensure loader.try &.close_all end @@ -203,43 +206,43 @@ describe Crystal::FFI::CallInterface do describe ".variadic" do it "basic" do - call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint16, [Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1 + call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1 loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH]) loader.load_library "sum" function_pointer = loader.find_symbol("sum_variadic") - return_value = 0_i32 + return_value = 0_i64 args = Int32[3, 1, 3, 5] arg_pointers = StaticArray(Pointer(Void), 4).new { |i| (args.to_unsafe + i).as(Void*) } call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) - return_value.should eq 9 + return_value.should eq 9_i64 ensure loader.try &.close_all end it "zero varargs" do - call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint16, [Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1 + call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1 loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH]) loader.load_library "sum" function_pointer = loader.find_symbol("sum_variadic") - return_value = 1_i32 - count = 0 + return_value = 1_i64 + count = 0_i32 arg_pointer = pointerof(count).as(Void*) call_interface.call(function_pointer, pointerof(arg_pointer), pointerof(return_value).as(Void*)) - return_value.should eq 0 + return_value.should eq 0_i64 ensure loader.try &.close_all end it "validates args size" do expect_raises Exception, "invalid value for fixed_args" do - Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint32, [] of Crystal::FFI::Type, 1 + Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [] of Crystal::FFI::Type, 1 end expect_raises Exception, "invalid value for fixed_args" do - Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint32, [] of Crystal::FFI::Type, -1 + Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [] of Crystal::FFI::Type, -1 end end end