在 ruby 上调用 c 函数时出现分段错误
segmentation fault when calling c function on ruby
我正在尝试使用 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] = '[=11=]';
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] = '[=11=]';
return str;
}
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '[=11=]'; 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] != '[=13=]'; 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\x00No error detected.\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"
当正确的必须只有:
"ruby"
编辑 3:
进行此更改:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '[=14=]'; 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] != '[=15=]'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new2(valor);
}
期待返回 "ruby" 字符串。但不是。它 returns: "\x05"
这是什么意思?
for (i = 0; i < length; i++)
在此循环中,如果条件递增 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]
不是有效访问,可能会导致崩溃
首先,让我感谢@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] != '[=10=]'; 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
我正在尝试使用 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] = '[=11=]';
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] = '[=11=]';
return str;
}
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '[=11=]'; 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] != '[=13=]'; 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\x00No error detected.\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"
当正确的必须只有:
"ruby"
编辑 3:
进行此更改:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '[=14=]'; 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] != '[=15=]'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new2(valor);
}
期待返回 "ruby" 字符串。但不是。它 returns: "\x05"
这是什么意思?
for (i = 0; i < length; i++)
在此循环中,如果条件递增 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]
不是有效访问,可能会导致崩溃
首先,让我感谢@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] != '[=10=]'; 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