Skip to content

Commit

Permalink
[ruby/fiddle] Use Ruby's true/false for C bool
Browse files Browse the repository at this point in the history
GitHub: fix ruby/fiddle#130

Reported by Benoit Daloze. Thanks!!!

ruby/fiddle@2640e0148e
  • Loading branch information
kou authored and hsbt committed Nov 8, 2023
1 parent d30ea58 commit 2a6d6d3
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 23 deletions.
21 changes: 21 additions & 0 deletions ext/fiddle/closure.c
Expand Up @@ -139,6 +139,20 @@ with_gvl_callback(void *ptr)
rb_ary_push(params,
rb_str_new_cstr(*((const char **)(x->args[i]))));
break;
case TYPE_BOOL:
if (sizeof(bool) == sizeof(char)) {
rb_ary_push(params, CBOOL2RBBOOL(*(unsigned char *)x->args[i]));
} else if (sizeof(bool) == sizeof(short)) {
rb_ary_push(params, CBOOL2RBBOOL(*(unsigned short *)x->args[i]));
} else if (sizeof(bool) == sizeof(int)) {
rb_ary_push(params, CBOOL2RBBOOL(*(unsigned int *)x->args[i]));
} else if (sizeof(bool) == sizeof(long)) {
rb_ary_push(params, CBOOL2RBBOOL(*(unsigned long *)x->args[i]));
} else {
rb_raise(rb_eNotImpError, "bool isn't supported: %u",
(unsigned int)sizeof(bool));
}
break;
default:
rb_raise(rb_eRuntimeError, "closure args: %d", type);
}
Expand Down Expand Up @@ -188,6 +202,13 @@ with_gvl_callback(void *ptr)
/* Dangerous. Callback must keep reference of the String. */
*((const char **)(x->resp)) = StringValueCStr(ret);
break;
case TYPE_BOOL:
if (sizeof(bool) == sizeof(long)) {
*(unsigned long *)x->resp = RB_TEST(ret);
} else {
*(ffi_arg *)x->resp = RB_TEST(ret);
}
break;
default:
rb_raise(rb_eRuntimeError, "closure retval: %d", type);
}
Expand Down
64 changes: 44 additions & 20 deletions ext/fiddle/conversions.c
Expand Up @@ -2,25 +2,6 @@

#include <fiddle.h>

VALUE
rb_fiddle_type_bool(void)
{
if (sizeof(bool) == sizeof(char)) {
return INT2NUM(TYPE_UCHAR);
} else if (sizeof(bool) == sizeof(short)) {
return INT2NUM(TYPE_USHORT);
} else if (sizeof(bool) == sizeof(int)) {
return INT2NUM(TYPE_UINT);
} else if (sizeof(bool) == sizeof(long)) {
return INT2NUM(TYPE_ULONG);
} else {
rb_raise(rb_eNotImpError,
"bool isn't supported: %u",
(unsigned int)sizeof(bool));
return RUBY_Qnil;
}
}

VALUE
rb_fiddle_type_ensure(VALUE type)
{
Expand Down Expand Up @@ -168,7 +149,7 @@ rb_fiddle_type_ensure(VALUE type)
return INT2NUM(TYPE_UINTPTR_T);
}
else if (type_id == bool_id) {
return rb_fiddle_type_bool();
return INT2NUM(TYPE_BOOL);
}
else {
type = original_type;
Expand Down Expand Up @@ -213,6 +194,21 @@ rb_fiddle_int_to_ffi_type(int type)
return &ffi_type_double;
case TYPE_CONST_STRING:
return &ffi_type_pointer;
case TYPE_BOOL:
signed_p = 0;
if (sizeof(bool) == sizeof(char)) {
return rb_ffi_type_of(char);
} else if (sizeof(bool) == sizeof(short)) {
return rb_ffi_type_of(short);
return INT2NUM(TYPE_USHORT);
} else if (sizeof(bool) == sizeof(int)) {
return rb_ffi_type_of(int);
} else if (sizeof(bool) == sizeof(long)) {
return rb_ffi_type_of(long);
} else {
rb_raise(rb_eNotImpError, "bool isn't supported: %u",
(unsigned int)sizeof(bool));
}
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
Expand Down Expand Up @@ -284,8 +280,23 @@ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
dst->pointer = rb_string_value_cstr(src);
}
break;
case TYPE_BOOL:
if (sizeof(bool) == sizeof(char)) {
dst->uchar = RB_TEST(*src);
} else if (sizeof(bool) == sizeof(short)) {
dst->ushort = RB_TEST(*src);
} else if (sizeof(bool) == sizeof(int)) {
dst->uint = RB_TEST(*src);
} else if (sizeof(bool) == sizeof(long)) {
dst->ulong = RB_TEST(*src);
} else {
rb_raise(rb_eNotImpError, "bool isn't supported: %u",
(unsigned int)sizeof(bool));
}
break;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
break;
}
}

Expand Down Expand Up @@ -344,6 +355,19 @@ rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
else {
return Qnil;
}
case TYPE_BOOL:
if (sizeof(bool) == sizeof(char)) {
return CBOOL2RBBOOL((unsigned char)retval.fffi_arg);
} else if (sizeof(bool) == sizeof(short)) {
return CBOOL2RBBOOL((unsigned short)retval.fffi_arg);
} else if (sizeof(bool) == sizeof(int)) {
return CBOOL2RBBOOL((unsigned int)retval.fffi_arg);
} else if (sizeof(bool) == sizeof(long)) {
return CBOOL2RBBOOL(retval.ulong);
} else {
rb_raise(rb_eNotImpError, "bool isn't supported: %u",
(unsigned int)sizeof(bool));
}
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
Expand Down
3 changes: 2 additions & 1 deletion ext/fiddle/conversions.h
Expand Up @@ -24,7 +24,6 @@ typedef union
void * pointer; /* ffi_type_pointer */
} fiddle_generic;

VALUE rb_fiddle_type_bool(void);
VALUE rb_fiddle_type_ensure(VALUE type);
ffi_type * rb_fiddle_int_to_ffi_type(int type);
void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst);
Expand All @@ -51,4 +50,6 @@ VALUE generic_to_value(VALUE rettype, fiddle_generic retval);
# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
#endif

#define CBOOL2RBBOOL(cbool) ((cbool) ? RUBY_Qtrue : RUBY_Qfalse)

#endif
8 changes: 7 additions & 1 deletion ext/fiddle/fiddle.c
Expand Up @@ -363,7 +363,7 @@ Init_fiddle(void)
*
* C type - bool
*/
rb_define_const(mFiddleTypes, "BOOL" , rb_fiddle_type_bool());
rb_define_const(mFiddleTypes, "BOOL" , INT2NUM(TYPE_BOOL));

/* Document-const: ALIGN_VOIDP
*
Expand Down Expand Up @@ -469,6 +469,12 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));

/* Document-const: ALIGN_BOOL
*
* The alignment size of a bool
*/
rb_define_const(mFiddle, "ALIGN_BOOL", INT2NUM(ALIGN_OF(bool)));

/* Document-const: WINDOWS
*
* Returns a boolean regarding whether the host is WIN32
Expand Down
1 change: 1 addition & 0 deletions ext/fiddle/fiddle.h
Expand Up @@ -126,6 +126,7 @@
#define TYPE_DOUBLE 8
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10
#define TYPE_BOOL 11

#define TYPE_INT8_T TYPE_CHAR
#define TYPE_UINT8_T -TYPE_INT8_T
Expand Down
2 changes: 2 additions & 0 deletions ext/fiddle/lib/fiddle/import.rb
Expand Up @@ -119,6 +119,8 @@ def sizeof(ty)
return SIZEOF_VOIDP
when TYPE_CONST_STRING
return SIZEOF_CONST_STRING
when TYPE_BOOL
return SIZEOF_BOOL
else
if defined?(TYPE_LONG_LONG) and
ty == TYPE_LONG_LONG
Expand Down
12 changes: 12 additions & 0 deletions ext/fiddle/lib/fiddle/pack.rb
Expand Up @@ -15,6 +15,7 @@ module PackInfo # :nodoc: all
TYPE_USHORT => ALIGN_SHORT,
TYPE_UINT => ALIGN_INT,
TYPE_ULONG => ALIGN_LONG,
TYPE_BOOL => ALIGN_BOOL,
}

PACK_MAP = {
Expand All @@ -30,6 +31,16 @@ module PackInfo # :nodoc: all
TYPE_UINT => "I!",
TYPE_ULONG => "L!",
}
case SIZEOF_BOOL
when SIZEOF_CHAR
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UCHAR]
when SIZEOF_SHORT
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_USHORT]
when SIZEOF_INT
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UINT]
when SIZEOF_LONG
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_ULONG]
end

SIZE_MAP = {
TYPE_VOIDP => SIZEOF_VOIDP,
Expand All @@ -43,6 +54,7 @@ module PackInfo # :nodoc: all
TYPE_USHORT => SIZEOF_SHORT,
TYPE_UINT => SIZEOF_INT,
TYPE_ULONG => SIZEOF_LONG,
TYPE_BOOL => SIZEOF_BOOL,
}
if defined?(TYPE_LONG_LONG)
ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[TYPE_ULONG_LONG] = ALIGN_LONG_LONG
Expand Down
8 changes: 7 additions & 1 deletion test/fiddle/test_c_struct_entry.rb
Expand Up @@ -8,7 +8,7 @@
module Fiddle
class TestCStructEntity < TestCase
def test_class_size
types = [TYPE_DOUBLE, TYPE_CHAR]
types = [TYPE_DOUBLE, TYPE_CHAR, TYPE_DOUBLE, TYPE_BOOL]

size = CStructEntity.size types

Expand All @@ -20,6 +20,12 @@ def test_class_size
expected = PackInfo.align expected, alignments[1]
expected += PackInfo::SIZE_MAP[TYPE_CHAR]

expected = PackInfo.align expected, alignments[2]
expected += PackInfo::SIZE_MAP[TYPE_DOUBLE]

expected = PackInfo.align expected, alignments[3]
expected += PackInfo::SIZE_MAP[TYPE_BOOL]

expected = PackInfo.align expected, alignments.max

assert_equal expected, size
Expand Down
12 changes: 12 additions & 0 deletions test/fiddle/test_closure.rb
Expand Up @@ -81,6 +81,18 @@ def call(string)
end
end

def test_bool
closure_class = Class.new(Closure) do
def call(bool)
not bool
end
end
closure_class.create(:bool, [:bool]) do |closure|
func = Function.new(closure, [:bool], :bool)
assert_equal(false, func.call(true))
end
end

def test_free
Closure.create(:int, [:void]) do |closure|
assert(!closure.freed?)
Expand Down
17 changes: 17 additions & 0 deletions test/fiddle/test_func.rb
Expand Up @@ -145,5 +145,22 @@ def to_str
assert_equal("string: He, const string: World, uint: 29\n",
output_buffer[0, written])
end

def test_rb_memory_view_available_p
omit "MemoryView is unavailable" unless defined? Fiddle::MemoryView
libruby = Fiddle.dlopen(nil)
case Fiddle::SIZEOF_VOIDP
when Fiddle::SIZEOF_LONG_LONG
value_type = -Fiddle::TYPE_LONG_LONG
else
value_type = -Fiddle::TYPE_LONG
end
rb_memory_view_available_p =
Function.new(libruby["rb_memory_view_available_p"],
[value_type],
:bool,
need_gvl: true)
assert_equal(false, rb_memory_view_available_p.call(Fiddle::Qnil))
end
end
end if defined?(Fiddle)

0 comments on commit 2a6d6d3

Please sign in to comment.