2013-04-11 63 views
3

由於工作版權問題,我無法發佈我的實際代碼,所以我會嘗試用簡單的示例代碼顯示我的問題。Ruby C擴展rb_str_new2似乎返回false

我有一個C擴展它的簡化版本是這樣的:

#include <ruby.h> 
#include <termios.h> 
#include <stdio.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

VALUE test(VALUE self, VALUE string); 
void Init_module_name() { 
    module_name = rb_define_module("Modulename"); 
    c_modulename = rb_define_class_under(modulename, "Class", rb_cObject); 
    rb_define_method(c_modulename, "test", test, 1); 

    e_ModuleNameError = rb_define_class_under(modulename, "Error", rb_eStandardError); 
} 

VALUE test(VALUE self, VALUE string) { 
    char *c_string = StringValueCStr(string); 
    int fd = open(c_string, O_RDWR | O_NOCTTY | O_NONBLOCK); 

    if (fd == -1) { 
     rb_raise(e_ModuleNameError, "Failed to open file"); 
    } 
    if (!isatty(fd)) { 
     rb_raise(e_ModuleNameError, "File is not a tty"); 
    } 

    struct termios config; 
    int termios_ret = init_termios(config, fd) 
    if (termios_ret != OK) { // OK defined by enum in modulename's header 
     close(fd); 
     rb_raise(e_ModuleNameError, "Termios init failed."); 
    } 

    int success = write(fd, "I'm a string", str_length); 
    if (success < str_length) { 
     close(fd); 
     rb_raise(e_ModuleNameError, "Failed to write to file."); 
    } 

    close(fd); 
    return rb_str_new2("Success"); 
} 

然後,要求這看起來Ruby代碼,如:

require 'modulename' 

class ModuleName 
    attr_acessor :file 

    def initialize(file) 
    @file = file 
    @object = Modulename::Class.new 
    end 

    def test 
    @object.test @file 
    end 
end 

然後叫我的生產項目,如:

require "modulename_ruby_file" 

x = ModuleName "/dev/pts/1" 
x.test 

這是有趣的事情。當我在生產中運行此代碼時,上面x.test的返回值是false(如字面意義上的值false,而不是字符串)。此外,寫入文件永遠不會發生。但是,如果我在一些簡化的測試代碼中執行它,它就會像預期的那樣返回字符串「Success」,並且寫入確實完成。

有誰知道,將導致此功能不執行寫操作,並返回false任何情況呢?我已經嘗試過對它進行救援,以防它拋出一個rb_raises,但它似乎不是。

我和我的3團隊的其他成員看着這一切的下午,並沒有找到答案。

+0

我認爲示例代碼需要一些編輯。例如,「@ console」是什麼?它實際上是「@ object」嗎? –

+1

就我所見,您的示例C擴展方法'test'將返回字符串'Success',或者引發錯誤。你真的能夠使用這段代碼複製錯誤嗎?我懷疑你選擇提取的部分很可能實際上並不能證明你的問題。 –

+1

事實上,我期望有一個環境問題,或者非常簡單的事情,比如在部署到生產環境時不重新構建擴展。 –

回答

3

終於想通了這一點,這是非常相似,@NeilSlater關於該問題的評論在說什麼。

我們增加了調試的一噸的C代碼,把它寫入日誌文件,想通了,C函數(在我的例子試驗)是從字面上從來沒有被調用。所以,我們查看了.so的符號表,並且彙編代碼gcc正在生成,並且都很好。最後我們只是說,「讓我們改變函數的名稱,看看是否有幫助」,並且......它的工作。實際的函數被命名爲logout,並將其更改爲project_name_logout,因此顯然存在某種名稱空間衝突。所以,就像@NeilSlater所說的那樣,這與環境有關!

所以,對任何人都對谷歌發現這樣的:通過在前面的所有功能與您的項目名稱添加一個「命名」你的C代碼,你應該能夠避免此問題。 [一個其他成員提到,事後,這是一個在C很好的做法反正]

注:我們沒有花時間去追查什麼用註銷碰撞。

+1

請[接受此答案](http://meta.stackexchange.com/a/5235/183358),以便在所有摘要中標記回答問題。這有助於那些想回答問題的人避免浪費時間在已經回答的問題上 –