I'm writing a Ruby C extension, and need to call rb_raise()
and pass it a char *
. I also need to free that given char *
. My current behavior won't free anything, and another approach I've tried lead me into undefined behavior. What is the correct way to do so ?
Here's a minimal example of my issue:
static VALUE
rb_some_function(VALUE self)
{
char *foo;
foo = malloc(100);
strcpy(foo, "message\0");
rb_raise(rb_eRuntimeError, "%s\n", foo);
free(foo); // This won't work since rb_raise exits the function using longjmp()
}
My idea would be to free
before rb_raise
. I've tried this with a tiny program, to check if it would lead to any leak:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void stuff(int i)
{
char *str;
str = malloc(100);
strcpy(str, "message\0");
free(str); // this feel very wrong to free and then use
printf("\r%s %i", str, i);
}
int main(int argc, char const *argv[])
{
// Time for instrument to attach.
sleep(5);
for (int i = 0; i < 1e6; i++) stuff(i);
printf("\n");
return 0;
}
It seems that this is safe from leak. But freeing before usage makes me think this can lead to troubles I don't known about. Like an undefined behavior as suggested in this answer.
Do you know a safe way rb_raise
and free
the string that contained the error message ?
How about use Ruby String object like this.
static VALUE
rb_some_function(VALUE self)
{
volatile VALUE str;
char *foo;
foo = malloc(100);
strcpy(foo, "message\0");
str = rb_str_new2(foo);
free(foo);
rb_raise(rb_eRuntimeError, "%s\n", StringValuePtr(str));
}
If you use a Ruby String object, it will be freed by ruby's garbage collector.