c-当ruby成功时,IRB无法运行ruby gem函数



我最近制作了以下红宝石宝石(称为sse(:

#include <ruby.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
/*
 * Module handle
*/
static VALUE sse_module;
/*
 * All exceptions for this module
*/
static VALUE sse_FileNotFoundError;
static VALUE sse_ForkFailureError;
static VALUE sse_PipeFailureError;
static VALUE sse_WriteFailureError;
static VALUE sse_ReadFailureError;
static VALUE sse_WaitpidFailureError;
static VALUE sse_TimeoutError;
/*
 * General utilities
*/
char **split(char *str, char *sep) {
    char *arg = strtok(str, sep);
    size_t arg_list_size = 1;
    char **arg_list = malloc(sizeof(char*));
    arg_list[0] = malloc(strlen(arg));
    strncpy(arg_list[0], arg, strlen(arg));
    while((arg = strtok(NULL, sep)) != NULL) {
        arg_list = realloc(arg_list, (sizeof(char*))*(arg_list_size+1));
        arg_list[arg_list_size] = malloc(strlen(arg));
        strncpy(arg_list[arg_list_size], arg, strlen(arg));
        ++arg_list_size;
    }
    arg_list = realloc(arg_list, (sizeof(char*))*(arg_list_size));
    arg_list[arg_list_size] = malloc(sizeof(char*));
    arg_list[arg_list_size] = (char*)NULL;
    return arg_list;
}
/*
 * Ruby classes and functions
*/
VALUE rb_execute_sh(VALUE self, VALUE rb_stdin, VALUE rb_timeout, VALUE rb_command) {
    int stdin_ends[2];
    int stdout_ends[2];
    int stderr_ends[2];
    if(pipe(stdin_ends) == -1 || pipe(stdout_ends) == -1 || pipe(stderr_ends) == -1) {
        rb_raise(sse_PipeFailureError, "%s:%d (%d) pipe: %sn", __FILE__, __LINE__, errno, strerror(errno));
    }
    char **command_list = split(StringValueCStr(rb_command), (char*)" ");
    char *stdin_buf = StringValueCStr(rb_stdin);
    pid_t pid = fork();
    if(pid > 0) {
        size_t stdout_buf_size = 0;
        size_t stderr_buf_size = 0;
        size_t stdout_buf_max = 1;
        size_t stderr_buf_max = 1;
        char *stdout_buf = malloc(1);
        char *stderr_buf = malloc(1);
        stdout_buf[0] = '';
        stderr_buf[0] = '';
        time_t start = time(NULL);
        time_t timeout = NUM2INT(rb_timeout);
        int sent_stdin = 0;
        close(stdin_ends[0]);
        close(stdout_ends[1]);
        close(stderr_ends[1]);
        while(difftime(time(NULL), start) < timeout) {
            int status = waitpid(pid, NULL, WNOHANG);
            if(status == -1) {
                rb_raise(sse_WaitpidFailureError, "%s:%d (%d) waitpid: %sn", __FILE__, __LINE__, errno, strerror(errno));
            } else if(status == 0) {
                fd_set write_set;
                fd_set read_set;
                struct timeval select_timeout = { 0, 0 };
                int maxfd = (stdin_ends[1] > stdout_ends[0] ? (stdin_ends[1] > stderr_ends[0] ? stdin_ends[1] : stderr_ends[0]) : (stdout_ends[0] > stderr_ends[0] ? stdout_ends[0] : stderr_ends[0]));
                FD_ZERO(&write_set);
                FD_ZERO(&read_set);
                if(sent_stdin == 0) {
                    FD_SET(stdin_ends[1], &write_set);
                }
                FD_SET(stdout_ends[0], &read_set);
                FD_SET(stderr_ends[0], &read_set);
                select(maxfd+1, &read_set, &write_set, NULL, &select_timeout);
                if(FD_ISSET(stdin_ends[1], &write_set)) {
                    sent_stdin = 1;
                    if(write(stdin_ends[1], stdin_buf, strlen(stdin_buf)) == -1) {
                        rb_raise(sse_WriteFailureError, "%s:%d (%d) write: %sn", __FILE__, __LINE__, errno, strerror(errno));
                    }
                    close(stdin_ends[1]);
                }
                if(FD_ISSET(stdout_ends[0], &read_set)) {
                    char tmp_buf[251];
                    ssize_t bytes_read = read(stdout_ends[0], tmp_buf, 250);
                    if(bytes_read == -1) {
                        rb_raise(sse_ReadFailureError, "%s:%d (%d) read: %sn", __FILE__, __LINE__, errno, strerror(errno));
                    }
                    tmp_buf[bytes_read] = '';
                    while((stdout_buf_size + bytes_read+1) >= stdout_buf_max) {
                        stdout_buf_max *= 2;
                        stdout_buf = realloc(stdout_buf, stdout_buf_max);
                    }
                    strncpy(stdout_buf, tmp_buf, bytes_read);
                    stdout_buf_size += bytes_read;
                    stdout_buf[stdout_buf_size] = '';
                }
                if(FD_ISSET(stderr_ends[0], &read_set)) {
                    char tmp_buf[251];
                    ssize_t bytes_read = read(stderr_ends[0], tmp_buf, 250);
                    if(bytes_read == -1) {
                        rb_raise(sse_ReadFailureError, "%s:%d (%d) read: %sn", __FILE__, __LINE__, errno, strerror(errno));
                    }
                    tmp_buf[bytes_read] = '';
                    while((stderr_buf_size + bytes_read+1) >= stderr_buf_max) {
                        stderr_buf_max *= 2;
                        stderr_buf = realloc(stderr_buf, stderr_buf_max);
                    }
                    strncpy(stderr_buf, tmp_buf, bytes_read);
                    stderr_buf_size += bytes_read;
                    stderr_buf[stderr_buf_size] = '';
                }
            } else {
                close(stdout_ends[0]);
                close(stderr_ends[1]);
                VALUE result = rb_ary_new2(3);
                rb_ary_store(result, 0, INT2NUM(difftime(time(NULL), start)));
                rb_ary_store(result, 1, rb_str_new_cstr(stdout_buf));
                rb_ary_store(result, 2, rb_str_new_cstr(stderr_buf));
                return result;
            }
        }
        kill(SIGINT, pid);
        rb_raise(sse_TimeoutError, "Proccess took too long to finish.n");
    } else if(pid == 0) {
        dup2(stdin_ends[0], STDIN_FILENO);
        dup2(stdout_ends[1], STDOUT_FILENO);
        dup2(stderr_ends[1], STDERR_FILENO);
        close(stdin_ends[1]);
        close(stdout_ends[0]);
        close(stderr_ends[0]);
        if(execvp(command_list[0], command_list) == -1) {
            rb_raise(sse_ForkFailureError, "%s:%d (%d) execvp: %sn", __FILE__, __LINE__, errno, strerror(errno));
        }
    } else {
        rb_raise(sse_FileNotFoundError, "%s:%d (%d) execvp: %sn", __FILE__, __LINE__, errno, strerror(errno));
    }
    VALUE thunderfury_blessed_blade_of_the_windseeker = rb_ary_new2(3);
    rb_ary_store(thunderfury_blessed_blade_of_the_windseeker, 0, INT2NUM(42));
    rb_ary_store(thunderfury_blessed_blade_of_the_windseeker, 1, rb_str_new_cstr("this is stdout"));
    rb_ary_store(thunderfury_blessed_blade_of_the_windseeker, 2, rb_str_new_cstr("this is stderr"));
    return thunderfury_blessed_blade_of_the_windseeker;
}
/*
 * Initialize the module
*/
void Init_sse() {
    sse_module = rb_define_module("sse");
    sse_FileNotFoundError = rb_define_class_under(sse_module, "FileNotFoundError", rb_eStandardError);
    sse_ForkFailureError = rb_define_class_under(sse_module, "ForkFailureError", rb_eStandardError);
    sse_PipeFailureError = rb_define_class_under(sse_module, "PipeFailureError", rb_eStandardError);
    sse_WriteFailureError = rb_define_class_under(sse_module, "WriteFailureError", rb_eStandardError);
    sse_ReadFailureError = rb_define_class_under(sse_module, "ReadFailureError", rb_eStandardError);
    sse_WaitpidFailureError = rb_define_class_under(sse_module, "WaitpidFailureError", rb_eStandardError);
    sse_TimeoutError = rb_define_class_under(sse_module, "TimeoutError", rb_eStandardError);
    rb_define_global_function("execute_sh", rb_execute_sh, 3);
}

当从脚本运行它时,它工作得很好:

admins-MacBook-Pro-2:sse-ruby nchambers$ cat client.rb
require './sse'
result = execute_sh('', 10, 'hostname')
puts "=>#{result[0]}<=n=>#{result[1]}<=n=>#{result[2]}<=n"
admins-MacBook-Pro-2:sse-ruby nchambers$ ruby client.rb
=>0<=
=>admins-MacBook-Pro-2.local
<=
=><=
admins-MacBook-Pro-2:sse-ruby nchambers$

然而,如果我从irb做同样的事情,我会得到:

admins-MacBook-Pro-2:sse-ruby nchambers$ irb
2.2.4 :001 > require './sse'
 => true
2.2.4 :002 > result = execute_sh('', 10, 'hostname')
 => [0, "n.2.4 :003 > :in `execute_sh'ntfrom (irb):2ntfrom /Users/nchambers/.rvm/rubies/ruby-2.2.4/bin/irb:11:in `<main>'n", "irb(6804,0x7fffa88db3c0) malloc: *** error for object 0x7ff9ece81880: pointer being freed was not allocatedn*** set a breakpoint in malloc_error_break to debugn"]
2.2.4 :003 > puts "=>#{result[0]}<=n=>#{result[1]}<=n=>#{result[2]}<=n"
=>0<=
=>
.2.4 :003 > :in `execute_sh'
    from (irb):2
    from /Users/nchambers/.rvm/rubies/ruby-2.2.4/bin/irb:11:in `<main>'
<=
=>irb(6804,0x7fffa88db3c0) malloc: *** error for object 0x7ff9ece81880: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
<=
 => nil
2.2.4 :004 >

我看不出为什么会发生这种事。所以我的问题是,为什么IRB会在脚本成功的地方失败?非常感谢。

arg_list[0] = malloc(strlen(arg));
strncpy(arg_list[0], arg, strlen(arg));
arg_list[arg_list_size] = malloc(strlen(arg));
strncpy(arg_list[arg_list_size], arg, strlen(arg));

arg_list[0] = malloc(strlen(arg) + 1);
strncpy(arg_list[0], arg, strlen(arg) + 1);
arg_list[0][strlen(arg)] = '';
arg_list[arg_list_size] = malloc(strlen(arg) + 1);
strncpy(arg_list[arg_list_size], arg, strlen(arg) + 1);
arg_list[arg_list_size][strlen(arg)] = '';

技术工作

arg_list[0] = strdup(arg);
arg_list[arg_list_size] = strdup(arg);

没关系,我想

这可能会达到您认为想要的效果,但并不能完全解决底层问题,即C

相关内容

  • 没有找到相关文章

最新更新