2013-04-11 1 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"); 
} 

그런 다음이 보이는 필요로하는 루비 코드와 같은 : 다음과 같은 내 생산 프로젝트라고

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가 말했듯이, 환경과 관련이 있습니다!

Google에서 이것을 찾는 다른 사용자를 위해 : 모든 기능 앞에 프로젝트 이름을 붙여서 C 코드에 "네임 스페이스"를 추가하면이 문제를 피할 수 있습니다. [다른 멤버들 중 한 명은 사실 C 어쨌든 좋은 연습이라고 언급했습니다.]

참고 : 로그 아웃과 충돌 한 내용을 추적하는 데 시간이 걸리지 않았습니다.

+1

질문에 대한 답변이 모든 요약에서 표시되도록 [대답에 동의하십시오] (http://meta.stackexchange.com/a/5235/183358)를 입력하십시오. 이것은 질문에 답하기를 원하는 사람들이 이미 응답 한 질문에 시간을 낭비하지 않도록 도와줍니다. –