【问题标题】:segmentation fault when calling c function on ruby在 ruby​​ 上调用 c 函数时出现分段错误
【发布时间】:2015-01-11 22:52:49
【问题描述】:

我正在尝试使用 C 函数扩展我的 Ruby 代码。 C 代码在没有警告的情况下编译。但是当我尝试运行 ruby​​ 代码时,我遇到了分段错误:

我有这个 c 代码:

#include <ruby.h>

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

#include "nessie.h"

/* #define TRACE_INTERMEDIATE_VALUES */

/*
 * The number of rounds of the internal dedicated block cipher.
 */
#define R 10

VALUE rb_mExample;
VALUE rb_cClass;

// ...

static char* displayHash(const unsigned char array[], int length){
  int i, k;
  char *str;

  str = malloc(3 * length + 1);
  if (str == NULL) {
    return NULL;
  }

  k = 0;
  str[0] = '\0';
  for (i = 0; i < length; i++){
    char hex[3];

    if (i % 32 == 0){
      str[k++] = ' ';
    }

    if (i % 8 == 0){
      str[k++] = ' ';
    }
    snprintf(hex, sizeof(hex), "%02X", array[i]);

    str[k++] = hex[0];
    str[k++] = hex[1];
  }

  str[k] = '\0';

  return str;
}


VALUE
print_string(VALUE class, VALUE *valor) {
  struct NESSIEstruct w;
  u8 digest[DIGESTBYTES];

  int i;
  for (i = 0; valor[i] != '\0'; i++);
  int sizeo = i;

  NESSIEinit(&w);
  NESSIEadd((u8*)valor, 8*sizeo, &w);
  NESSIEfinalize(&w, digest);

  return (VALUE) displayHash(digest, DIGESTBYTES);
}

void
Init_example(){
  rb_mExample = rb_define_module("Example");
  rb_cClass = rb_define_class_under(rb_mExample, "Class", rb_cObject);

  rb_define_method(rb_cClass, "print_string", print_string, 1);
}

还有这段 Ruby 代码:

require "example"

def print
  e = Example::Class.new
  e.print_string("ruby")
end

当我运行 ruby​​ 代码时,我遇到了分段错误。

编辑:带有日志信息的要点

https://gist.github.com/psantos10/f07484afa26ce0e55181

我哪里失败了?我是 C 语言的新手。

编辑:

我将“print_string”更改为如下所示:

VALUE
print_string(VALUE class, VALUE *valor) {
  struct NESSIEstruct w;
  u8 digest[DIGESTBYTES];

  int i;
  for (i = 0; valor[i] != '\0'; i++);
  int sizeo = i;

  NESSIEinit(&w);
  NESSIEadd((u8*)valor, 8*sizeo, &w);
  NESSIEfinalize(&w, digest);

  return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}

这样,分段错误就消失了。但是返回的字符串带有一个奇怪的字符,例如:

"ruby\x00\x00\x00\x00\x00未检测到错误。\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD80x\xC0 \x18`\x18\x18&F\xAF\x05#\x8C##\xB8\x91\xF9~\xC6?\xC6\xC6\xFB\xCDo\x13\xE8\x87\xE8\xE8\xCB\x13\xA1L \x87&\x87\x87\x11mb\xA9\xB8\xDA\xB8\xB8\t\x02\x05\b\x01\x04\x01\x01\r\x9EnBO!OO\x9Bl\xEE\xAD6\xD866\xFFQ \x04Y\xA6\xA2\xA6\xA6\f\xB9\xBD\xDE\xD2o\xD2"

当正确时必须只有:

“红宝石”

编辑 3:

进行此更改:

VALUE
print_string(VALUE class, VALUE *valor) {
  struct NESSIEstruct w;
  u8 digest[DIGESTBYTES];
 /*
  int i;
  for (i = 0; valor[i] != '\0'; i++);
  int sizeo = i;
 */
  NESSIEinit(&w);
  NESSIEadd((u8*)"ruby", 8*4, &w);
  NESSIEfinalize(&w, digest);

  return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}

返回正确的值。

然后我尝试这样做:

VALUE
print_string(VALUE class, VALUE *valor) {
  struct NESSIEstruct w;
  u8 digest[DIGESTBYTES];
 /*
  int i;
  for (i = 0; valor[i] != '\0'; i++);
  int sizeo = i;
 */
  NESSIEinit(&w);
  NESSIEadd((u8*)"ruby", 8*4, &w);
  NESSIEfinalize(&w, digest);

  return rb_str_new2(valor);
}

期望返回“ruby”字符串。但不是。它返回:“\x05”

这是什么意思?

【问题讨论】:

  • 您不能只将 c 字符串转换为/从 VALUE 转换 - 您需要使用适当的转换函数 - 请参阅 docs.ruby-lang.org/en/2.2.0/README_EXT.html
  • @FrederickCheung 使用“rb_str_new”作为文件说,我现在可以返回一个字符串。但是附加了奇怪的字符。请查看我的编辑
  • 您已将 128 作为最后一个参数传递给 rb_str_new,因此您将返回 128 字节长的内容
  • @FrederickCheung 请看我的编辑#3
  • 仅更改函数签名不会更改您传递的数据

标签: c ruby segmentation-fault


【解决方案1】:
for (i = 0; i < length; i++)

在这个循环中,对于每个传递的 if 条件,您都会增加 k,因此这样做您将获得数组超出范围的访问权限,从而导致崩溃。

确保

char *str = malloc( 3 * length + 1);

不是

char *str = malloc( 3 * (length + 1));

例如:

值为length = 2;

char *str = malloc(7);

现在在 for 循环中,您将 k 递增 4 次。

k = 4;

现在在第二次迭代之后,如果你退出循环,那么

k=8;

所以str[8] 不是有效的访问权限,可能会导致崩溃

【讨论】:

  • 但是这段代码,如果我返回一个 char * ,并在 C 上测试它的工作原理。仅当我返回 VALUE 类型时才会发生此错误
【解决方案2】:

首先,让我感谢@FrederickCheung 给了我正确的方向。

解决方案代码为:

VALUE
print_string(VALUE class, VALUE valor) {
  struct NESSIEstruct w;
  u8 digest[DIGESTBYTES];
  VALUE info;

  // Note here I must convert the Ruby VALUE type to C type. Thats is the trick. 
  char* valor2 = RSTRING_PTR(valor);

  int i;
  for (i = 0; valor2[i] != '\0'; i++);
  int sizeo = i;

  NESSIEinit(&w);
  NESSIEadd((u8*)valor2, 8*sizeo, &w);
  NESSIEfinalize(&w, digest);

  info = rb_str_new_cstr(displayHash(digest, DIGESTBYTES));

  return info;
}

想查看这段代码在哪里使用的可以访问:https://github.com/AngoDev/kryptonita

【讨论】:

    猜你喜欢
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2011-01-08
    相关资源
    最近更新 更多