rb_raise 之后的空闲字符串

free string after rb_raise

我正在编写 Ruby C 扩展,需要调用 rb_raise() 并向其传递一个 char *。我还需要释放给定 char *。我当前的行为不会释放任何东西,而我尝试过的另一种方法会导致我出现未定义的行为。这样做的正确方法是什么?

这是我的问题的一个简单示例:

static VALUE
rb_some_function(VALUE self)
{
    char *foo;
    
    foo = malloc(100);
    strcpy(foo, "message[=11=]");
    
    rb_raise(rb_eRuntimeError, "%s\n", foo);
    free(foo); // This won't work since rb_raise exits the function using longjmp()
}

我的想法是 freerb_raise 之前。我已经用一个小程序试过了,检查它是否会导致任何泄漏:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void stuff(int i)
{
    char *str;

    str = malloc(100);
    strcpy(str, "message[=12=]");
    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;
}

看来这是安全的,不会泄漏。但是在使用前释放让我觉得这会导致我不知道的麻烦。就像 .

中建议的 未定义行为

你知道安全的方法吗 rb_raisefree 包含错误消息的字符串?

像这样使用 Ruby 字符串对象怎么样。

static VALUE
rb_some_function(VALUE self)
{
    volatile VALUE str;
    char *foo;
    
    foo = malloc(100);
    strcpy(foo, "message[=10=]");
    
    str = rb_str_new2(foo);
    free(foo); 

    rb_raise(rb_eRuntimeError, "%s\n", StringValuePtr(str));
}

如果您使用 Ruby String 对象,它将被 ruby 的垃圾收集器释放。