Ruby extensions on 64 bit linux

* Don't assume a pointer and an int are the same size
* Don't make assumptions about the relative size of variable types
* Be wary of sign extension problems
* Use pointer arithmetic rather than address arithmetic
* Never cast malloc
* Explicitly include header files (-Wall will warn you about implicit
declarations)
* Watch out for data truncation, e.g. passing a size_t to something that
expects an int.
* Pack (align) your data structures as tightly as possible
* Watch out for data loss in constant expressions
* Use %p in your (s)printf's as appropriate
* Use #ifdef _LP64 as needed (or is that Solaris only?)

Regards,

Dan

···

-----Original Message-----
From: Joe Van Dyk [mailto:joevandyk@gmail.com]
Sent: Monday, July 25, 2005 12:24 PM
To: ruby-talk ML
Subject: Ruby extensions on 64 bit linux

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/149446
makes me wonder, when writing C extensions, are there
anything I should be watching out for when intending the code
to be run on a 64 bit OS?

Thanks,
Joe

Berger, Daniel wrote:

> From: Joe Van Dyk [mailto:joevandyk@gmail.com]
> Sent: Monday, July 25, 2005 12:24 PM
> To: ruby-talk ML
> Subject: Ruby extensions on 64 bit linux
>
>
> http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/149446
> makes me wonder, when writing C extensions, are there
> anything I should be watching out for when intending the code
> to be run on a 64 bit OS?
>
> Thanks,
> Joe

* Don't assume a pointer and an int are the same size
* Don't make assumptions about the relative size of variable types
* Be wary of sign extension problems
* Use pointer arithmetic rather than address arithmetic
* Never cast malloc
* Explicitly include header files (-Wall will warn you about implicit
declarations)
* Watch out for data truncation, e.g. passing a size_t to something that
expects an int.
* Pack (align) your data structures as tightly as possible
* Watch out for data loss in constant expressions
* Use %p in your (s)printf's as appropriate
* Use #ifdef _LP64 as needed (or is that Solaris only?)

Regards,

Dan

That is a nice list. It seems the first bullet on your list causes the
majority of problems. From ruby.h:

#if SIZEOF_LONG != SIZEOF_VOIDP
# error ---->> ruby requires sizeof(void*) == sizeof(long) to be
compiled. <<----
#endif
typedef unsigned long VALUE;
typedef unsigned long ID;

···

> -----Original Message-----

----
On the vast majority of 64bit systems/compilers sizeof(long) >
sizeof(int), however on many 32bit systems sizeof(long) == sizeof(int).
When the type of a function return value is unknown most/all compilers
default to int. If you have the following statement in your code

VALUE obj = my_func(arg);

(where my_func() returns a VALUE) and do not define or give a function
prototype for my_func() prior to the statement the result of my_func()
will be cast to an int (by default) and then cast to a VALUE, causing
truncation on most 64 bit systems. Turning warnings on catches these
kind of errors.

Adding to the list:
* turn on warnings
* use ANSI C function prototypes

FYI: the current Ruby sources do not always this :frowning:

-Charlie

Daniel,

What do you mean by “never cast malloc”?

···

--
Daniel Brockman <daniel@brockman.se>

Berger, Daniel wrote:

From: Joe Van Dyk [mailto:joevandyk@gmail.com] Sent: Monday, July 25, 2005 12:24 PM
To: ruby-talk ML
Subject: Ruby extensions on 64 bit linux

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/149446
makes me wonder, when writing C extensions, are there anything I should be watching out for when intending the code to be run on a 64 bit OS?

Thanks,
Joe

* Don't assume a pointer and an int are the same size
* Don't make assumptions about the relative size of variable types
* Be wary of sign extension problems
* Use pointer arithmetic rather than address arithmetic
* Never cast malloc
* Explicitly include header files (-Wall will warn you about implicit
declarations)
* Watch out for data truncation, e.g. passing a size_t to something that
expects an int.
* Pack (align) your data structures as tightly as possible

Nice list. I would only possibly take exception to this one. Since there is no standard way to pack C structs, I'd prefer to simply say don't make any assumptions about how the compiler will layout structs. The only reason this matters usually is when you want to serialize or deserialize a struct, and you take the shortcut of just writing/reading the whole struct as a single block instead of handling each field individually.

Adam

···

-----Original Message-----

* Watch out for data loss in constant expressions
* Use %p in your (s)printf's as appropriate
* Use #ifdef _LP64 as needed (or is that Solaris only?)

Regards,

Dan

Yeah, I had no idea what he was talking about, but didn't want to look
stupid. :frowning:

···

On 7/25/05, Daniel Brockman <daniel@brockman.se> wrote:

Daniel,

What do you mean by "never cast malloc"?

Joe Van Dyk wrote:

> Daniel,
>
> What do you mean by "never cast malloc"?

Yeah, I had no idea what he was talking about, but didn't want to look
stupid. :frowning:

Because it masks failed inclusion of <stdlib.h>. (If stdlib is not
included then the prototype for malloc is not defined causing malloc to
return an int and you run into the problem discussed earlier.) Also it
is not necessary in ANSI C:
http://www.eskimo.com/~scs/C-faq/q7.7.html

This is not really a problem with Ruby extensions though since Ruby
defines its own mem allocation functions / macros.

-Charlie

···

On 7/25/05, Daniel Brockman <daniel@brockman.se> wrote:

"Charles Mills" <cmills@freeshell.org> writes:

If stdlib is not included then the prototype for malloc is
not defined causing malloc to return an int and you run
into the problem discussed earlier.

Ah, of course. Interesting, I never thought of that.

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.