【问题标题】:free string after rb_raiserb_raise 之后的空闲字符串
【发布时间】:2020-11-14 13:48:12
【问题描述】:

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

这是我的问题的一个最小示例:

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()
}

我的想法是在rb_raise 之前发送free。我用一个小程序试过这个,检查它是否会导致任何泄漏:


#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;
}

这似乎是安全的,不会泄漏。但是在使用前释放让我认为这会导致我不知道的麻烦。就像this answer 中建议的未定义行为

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

【问题讨论】:

  • '这不起作用,因为 rb_raise'......rb_raise() 坏了,修复它。
  • @Martin James,rb_raise 是 ruby​​ 核心 API 的 psrt。我几乎不相信它已经坏了,无论如何也无法改变它。它在内部使用 longjmp。无论如何,不​​幸的是,修复 rb_raise 不是一个可接受的解决方案。如果您是反对者,请告诉我如何改进我的问题。我已经链接了 rb_raise 参考。
  • 好的,那么你调用/使用 rb_raise() 的方式就很糟糕了。释放空间然后访问它是 100% 错误的,并且用未定义的行为掩盖了问题的根本原因。
  • 好的,感谢您消除对此的怀疑。但是问题仍然存在,我该如何使用该功能并释放内存。也许这对于了解 ruby​​ C API 的人来说是一个问题,我也在澄清介绍
  • 使用静态数组而不是分配内存,也许吧?

标签: c ruby ruby-c-extension


【解决方案1】:

像这样使用 Ruby String 对象怎么样。

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));
}

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

【讨论】:

  • 是的,这看起来是利用 ruby​​ 的 gc 功能同时避免为简单字符串创建 RData 的最佳解决方案!谢谢!只是一个问题:你为什么将 str 标记为 volatile ?
  • 很抱歉让您感到困惑。这是一种习惯 :-) 实际上,这是防止 'str' 引用的对象被 GC 扫过的习惯用法。在这个小代码中你可能不需要它。但我把它放在安全的地方,因为我还没有看到你的代码的完整形式。 FIY,现在推荐to use a macro called RB_GC_GUARD() instead of 'volatile' modifier
猜你喜欢
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 2023-02-24
  • 2015-03-22
  • 2021-10-14
  • 2018-04-30
  • 1970-01-01
  • 2012-04-26
相关资源
最近更新 更多