# Ruby arguments into C function are warped

**URL:** <https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684>\
**Category:** Ruby\
**Created:** [December 31, 2008, 10:19pm UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684 "2008-12-31T22:19:41Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 31, 2008, 10:19pm UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684/1 "2008-12-31T22:19:41Z")

</div>

I want to code a few methods in C for speed reasons. The Pick Axe book  
(2nd edition) is a wonderful guide to writing Ruby code in C, but that’s  
not what I want. The benchmarks I ran for the Ruby-in-Ruby and Ruby-in-C  
programs showed similar results. So allow me to clarify:

I do not want a Ruby array in C. I want a C array in C.

Which I have done…

int array[1000000];

static VALUE t\_add(VALUE self, VALUE obj, VALUE i)  
{  
array[i] = obj;  
return 1;  
}

static VALUE t\_include(VALUE self, VALUE obj)  
{  
int size = sizeof(array) / sizeof(int);  
int index;

for(index = 0; index \< size; index++) {  
if(FIX2INT(obj) == FIX2INT(array[index])) {  
return Qtrue;  
}  
}

return Qfalse;  
}

static VALUE t\_at(VALUE self, VALUE obj)  
{  
return array[obj];  
}

The value of “obj” comes from within Ruby (IRB, actually). But unless I  
coerce it using FIX2INT, it’s always a weird value. Say I put in 1,  
it’ll tell me it received 31478 or something similar.

Another thing… I thought that if I passed in an ‘a’ or any other  
non-integer value into the add method, I’d get an error. I don’t. In  
fact…

require ‘my\_test’  
mt = MyTest.new  
mt.add(‘a’, 0)  
mt.at(0) # ‘a’

But…

mt.include?(‘a’) # false

So… what’s happening to my arguments as they pass through Ruby and  
into C?

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 31, 2008, 11:49pm UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684/2 "2008-12-31T23:49:34Z")

</div>

Daniel W. wrote:

> {
> 
> into C?  
> Notice that you’ve declared the arguments to t\_add as VALUEs, not ints.  
> This is because Ruby passes VALUE arguments to your function. A VALUE is  
> a reference to a Ruby object. If you want to store the arguments in an  
> int array, convert the objects to ints via FIX2INT or some other  
> conversion function:

static VALUE t\_add(VALUE self, VALUE obj, VALUE i)  
{  
array[FIX2INT(i)] = FIX2INT(obj);  
return self;  
}

A VALUE can reference any Ruby object, but the FIX2INT macro expects its  
argument to be a Ruby Fixnum. If it’s not, it will raise an exception.  
You’ll get an exception if you call mt.add(“a”, 0).

Also, the return value from t\_add should be a VALUE, not an int. It’s  
your choice which VALUE to return. Here I chose self.

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [January 1, 2009, 6:28am UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684/3 "2009-01-01T06:28:49Z")

</div>

Also: not a Ruby issue, but a C issue: You’ve left yourself wide open  
for a buffer overflow. Unless your Ruby code somehow guarantees that  
the value of i will always be within the range 0…999999 (in which  
case it really should be documented, and probably in a Ruby CONSTANT  
and C #define), it’s inevitable that some day some code will pass in a  
negative value, or a value of 1000000 or greater, and your code will  
mysteriously stop working correctly. Make sure, every time you access  
your array, but especially when assigning to it, that you check that  
the index is valid.

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [January 3, 2009, 1:05am UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684/4 "2009-01-03T01:05:41Z")

</div>

Tim H. wrote:

> A VALUE can reference any Ruby object, but the FIX2INT macro expects its  
> argument to be a Ruby Fixnum. If it’s not, it will raise an exception.  
> You’ll get an exception if you call mt.add(“a”, 0).

Ah, that seems obvious now. Thanks for the help.

> Also, the return value from t\_add should be a VALUE, not an int. It’s  
> your choice which VALUE to return. Here I chose self.

Agreed, and I originally was returning self (it’s still commented in the  
actual file) but I was trying to strip out all unnecessary code.

> Also: not a Ruby issue, but a C issue: You’ve left yourself wide open  
> for a buffer overflow.

Fully aware, but thanks for the concern. 😉

Brian C. wrote:

> Have a look at the RubyInline gem, and FFI

I’ve looked at RubyInline, and it was surprisingly easy to get it  
working. I’m uncertain if it will do what I need it do though – namely,  
pass information back and forth between C and Ruby.

The FFI project looks interesting though… 🙂

Thanks for the excellent replies.

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [January 1, 2009, 9:51am UTC](https://www.ruby-forum.com/t/ruby-arguments-into-c-function-are-warped/156684/5 "2009-01-01T09:51:28Z")

</div>

Have a look at the RubyInline gem, and FFI
