About rust ffi double pointer type


#1

Rust code

extern crate libc;

use libc::{c_char, c_int, c_void, c_ulong};

use std::ffi::{CString, CStr};
use std::mem;

#[repr(C)]
pub struct Row {
    pub count: c_ulong,
    pub columns: *const *const c_void
}

#[repr(C)]
pub struct Table {
    pub count: c_ulong,
    pub rows: *const *const Row
}

#[no_mangle]
pub unsafe extern fn test() -> *const Table {
    let mut tables: Vec<*const Row> = Vec::new();

    let mut s: Vec<*const c_void> = Vec::new();

    for x in 0..10 {
        s.push(CString::new("test").unwrap().into_raw() as *const c_void)
    }

    tables.push(mem::transmute(Box::new(Row{
        count: 10,
        columns: s.as_ptr()
    })));

    mem::transmute(Box::new(Table{
        count: 1,
        rows: tables.as_ptr()
    }))
}

test.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "rust_struct.h"

int
main(int argc, char **argv) {
    table *result = test();
    printf("count: %d\n", result->count);
    for (int i = 0; i < result->count; ++i)
    {
        printf("columns: %d\n", result->rows[i]->count);
        for (int j = 0; j < result->rows[i]->count; ++j)
        {
            printf("column %d: %s\n", j, result->rows[i]->columns[j]);
        }
    }
}

rust_struct.h

#ifndef H_RUST_STRUCT
#define H_RUST_STRUCT

typedef struct _row {
    int count;
    void **columns;
} row;

typedef struct _table {
    int count;
    row **rows;
} table;

table *test();

#endif

i don’t know how to set double pointer on rust

when i try run test program i got this

count: 1
columns: 10
Segmentation fault: 11

#2

I think the problem is the call to as_ptr on the tables and s Vecs. You are yielding a pointer to the data, but at the end of the test function they will be dropped and the memory freed. You probably want to call into_boxed_slice and then into_raw (or transmute like you already did with the boxes)


#3

Yeah I notice that, but i don’t know how to hold on in memory. tank you.


#4

You can convert Vecs to boxed slices using into_boxed_slice(), and then make Rust “forget” the box using Box::into_raw().

The caveat is that to properly free the memory afterwards, you’ll have to get back your box (from_raw()) and drop it.


#5

Thank you it’s worked.