在ruby上调用c函数时出现分段错误

在ruby上调用c函数时出现分段错误,c,ruby,segmentation-fault,C,Ruby,Segmentation Fault,我试图用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

我试图用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代码时,我遇到了一个分段错误

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

我在哪里失败?我是C语言新手

编辑:

我将“打印字符串”更改为如下所示:

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);
}
这样,分割错误就消失了。但是返回的字符串带有一个奇怪的字符,如:

\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\\\\02\x05\b\x01\x04\x01\x01\r\x9EnBO!OO\x9Bl\xEE\xAD6\xD866\xfq\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”

这是什么意思

for (i = 0; i < length; i++)
不是

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

值为
length=2;

char *str = malloc(7);
现在在for循环中,您将递增
k
4次

k = 4;
现在,在第二次迭代之后,如果退出循环

k=8;

因此,
str[8]
不是一个有效的访问权限,可能会导致崩溃

首先,让我感谢@frederickheung为我提供了正确的方向

解决方案代码为:

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

对于想要查看此代码在何处使用的用户,可以访问:

您不能仅将c字符串转换为值-您需要使用适当的转换函数-请参阅@FrederickCheung using“rb_str_new”“正如文档所说,我现在可以返回一个字符串。但是附加了奇怪的字符。请查看我的编辑您已将128作为最后一个参数传递给rb_str_new,因此您将返回128字节long@FrederickCheung请参阅我的编辑#3仅更改函数签名并不会更改您传递的数据,但如果我返回一个char*,则此代码将在C上测试其效果。仅当我返回值类型时,才会发生此错误
k=8;
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;
}