Home > OS >  Wrong arguments at ruby API in c-level
Wrong arguments at ruby API in c-level

Time:12-26

I created ruby method in C using Ruby API which receive 3 string arguments:

VALUE cache_class = rb_define_class_under(class, CACHE_CLASS_NAME, rb_cObject);

rb_define_method(cache_class, "cache_test_result", cache_test_result, 3);

In test.rb I called method:

Cache.new.cache_test_result("str1", "str2", "str3")

And C cache_test_result function works strange:

VALUE cache_test_result(VALUE str1, VALUE str2, VALUE str3) {
   int rstr1_len = RSTRING_LEN(str1)   1;
   char buf_str1[rstr1_len];
   strlcpy(buf_str1, RSTRING_PTR(str1), rstr1_len);

   int rstr2_len = RSTRING_LEN(str2)   1;
   char buf_str2[rstr2_len];
   strlcpy(buf_str2, RSTRING_PTR(str2), rstr2_len);

   int rstr3_len = RSTRING_LEN(str3)   1;
   char buf_str3[rstr3_len];
   strlcpy(buf_str3, RSTRING_PTR(str3), rstr3_len);

   printf("buf_str1: %s\n", buf_str1);
   printf("buf_str2: %s\n", buf_str2);
   printf("buf_str3: %s\n", buf_str3);
}

output of this function:

buf_str1: 
buf_str2: str1
buf_str3: str2

why args has offset...?

CodePudding user response:

To quote the documentation:

The first argument of the C function is the self, the rest are the arguments to the method.

Which means you need to adjust the function prototype and add an additional parameter, e.g.:

VALUE cache_test_result(VALUE self, VALUE str1, VALUE str2, VALUE str3) {

And since a C object of type VALUE can be everything (a Ruby string, integer or nil) never use RSTRING_{PTR,LEN} and similar (macro) functions without being sure of its Ruby type. Instead you may use Check_Type, StringValuePtr, or StringValueCStr depending on the use case.

Your example could be rewritten as:

VALUE cache_test_result(VALUE self, VALUE str1, VALUE str2, VALUE str3) {
   // Check if each value is a Ruby string
   // (or can be implicitly converted to one) and
   // return a pointer to its underlying C string.
   // It it also checked if the Ruby string contains NUL.
   // If any check fails an exception is raised.
   const char *buf_str1 = StringValueCStr(str1);
   const char *buf_str2 = StringValueCStr(str2);
   const char *buf_str3 = StringValueCStr(str3);
   // print each underlying C string
   printf("buf_str1: %s\n", buf_str1);
   printf("buf_str2: %s\n", buf_str2);
   printf("buf_str3: %s\n", buf_str3);
}
  • Related