I am working with the Ruby C API. I need to create a struct from within a function but I think I am making some allocation error. This is my code
#include <stdio.h>
#include <ruby.h>
#include <ruby/thread.h>
typedef struct {
double *matrix;
int nrows;
int ncols;
}Matrix;
void createMatrix(VALUE matrix, Matrix *mat) {
printf("In\n");
mat->nrows = RARRAY_LEN(matrix);
VALUE firstElement = rb_ary_entry(matrix, 0);
mat->ncols = RARRAY_LEN(firstElement);
printf("Matrix shape: (%d,%d)\n", mat->nrows, mat->ncols);
int i,j;
double *tempMat = (double *)malloc(mat->nrows * mat->ncols * sizeof(double));
printf("Allocated\n");
VALUE row;
for (i=0; i<mat->nrows; i++)
{
row = rb_ary_entry(matrix, i);
for (j=0; j<mat->ncols; j++)
{
tempMat[i * mat->ncols + j] = NUM2DBL(rb_ary_entry(row, j));
// printf("Matrix A Element(%d,%d)=%f\n", i, j, matA[i * colsA + j]);
}
}
mat->matrix = tempMat;
for (i=0; i<mat->nrows; i++)
{
for (j=0; j<mat->ncols; j++)
{
printf("Matrix temp Element(%d,%d)=%f\n", i, j, mat->matrix[i * mat->ncols + j]);
}
}
printf("Assigned\n");
return;
}
VALUE matmat_mul(VALUE self, VALUE matrixA, VALUE matrixB)
{
int i,j;
Matrix *matA;
createMatrix(matrixA, matA);
Matrix *matB;
createMatrix(matrixB, matB);
return Qnil;
}
void Init_la_ruby_ext()
{
VALUE rg = rb_define_module("RG");
VALUE linalg = rb_define_module_under(rg, "LinearAlgebra");
VALUE operation = rb_define_class_under(linalg, "Operation", rb_cObject);
rb_define_method(operation, "matmat_mul", matmat_mul, 2);
}
The extconf.rb
file is
require 'mkmf'
extension_name = 'la_ruby_ext'
create_makefile(extension_name)
and you can run the test with
require './la_ruby_ext'
rows = 3
cols = 3
mat = Array.new(rows){Array.new(cols)}
mat[0] = [0.0, 1.0, 2.0]
mat[1] = [3.0, 4.0, 5.0]
mat[2] = [6.0, 7.0, 8.0]
operation = RG::LinearAlgebra::Operation.new
matC = operation.matmat_mul(mat, mat.transpose)
As you can see from running the test the code gives segmentation fault the second time I call the function createMatrix
. This is my understanding:
struct Matrix
createMatrix
Any idea? Is this the right way to do this?
Given the definition void createMatrix(VALUE xxx, Matrix *mat)
and the use of mat->nrows = …
etc inside the function, the calls to createMatrix()
in matmul_mul()
are wrong.
You have:
VALUE matmat_mul(VALUE self, VALUE matrixA, VALUE matrixB)
{
int i,j;
Matrix *matA;
createMatrix(matrixA, matA);
Matrix *matB;
createMatrix(matrixB, matB);
You need:
VALUE matmat_mul(VALUE self, VALUE matrixA, VALUE matrixB)
{
int i,j;
Matrix matA;
createMatrix(matrixA, &matA);
Matrix matB;
createMatrix(matrixB, &matB);
In the current code, you pass uninitialized pointers to createMatrix()
and then assign to the 'random' memory that the pointers point at. This seldom leads to happiness. In the revised code, you have a pair of Matrix
values and you pass the pointers to those to the createMatrix()
function, which then fills in the details for you.