1
votes

I've built a link with my c library and the call of a specific function gives me a non-helpful error message (probably because i'm using unsafe {} decorator).

The message is:

./build.sh: line 7: 44630 Bus error: 10 cargo run --example ferris-astro-example

and the line 7 is

cargo run --example ferris-astro-example

Until now, with this C library, I compiled without error for 2 other functions, but for the last one it doesn't work.

The code in the documentation interface of the C library is :

char *swe_version(char *svers);

/* svers is a string variable with sufficient space to contain the version number (255 char) */

The doc says:

The function returns a pointer to the string svers, i.e. to the version number of the Swiss Ephemeris that your software is using.

And that is what I have written in rust:

  use std::os::raw::c_char;                                                                                                                                                                 
  #[link(name = "swe")]                                                                             
  extern "C" {                                                                                      
     // ... (other function)
     pub fn swe_version(s_version: *mut c_char) -> *mut c_char;
  }

and then the code is called by

let version: *mut c_char = "\0".as_bytes().as_ptr() as *mut c_char;
unsafe {
    // ... 
    // Get the version
    raw::swe_version(version);
    // ...
    }
// ...

I'm sure that the error is a mistake of version because no

version = raw::swe_version(version)

EDIT some hour later...

I found a solution to compile without error :

use std::os::raw::c_uchar;
use std::ptr;
mod raw;
pub fn test_lib() {
    let version = ptr::null_mut() as *mut c_uchar;
    unsafe {
        raw::swe_version(&version);
        // Free memory
        raw::swe_close();
    }
}

And raw :

use std::os::raw::c_uchar;

#[link(name = "swe")]
extern "C" {
    // pub fn swe_test(path: *const c_char); // swe_test try
    // pub fn swe_set_ephe_path(path: *const c_uchar);
    /// Version
    pub fn swe_version(s_version: &*mut c_uchar) -> *mut c_uchar;
    /// Free memory
    pub fn swe_close();
}

Thank you carton for helping, the debugger says me the same :

<read memory from 0x38302e32 failed (0 of 1 bytes read)>

I don’t find the solution on internet/book to define an array of 255 c_uchar.

I tried cast with *mut [c_uchar] and * mut Vec without success.

But c_uchar is unsigned 0 to 255 ? (before I used c_char) and c_schar is -128 - > 128

Edit 2

I can't get work your code and some variations.

I'm not sure if the array [0, 255] is the good solution, this gives me an array of integer

This code works witouth break/segemant fault:

use std::os::raw::c_char;
use std::ptr;
mod raw;
pub fn test_lib() {
    let version = ptr::null_mut() as *mut [c_char; 255];
    unsafe {
        raw::swe_version(&version);
        // Free memory
        raw::swe_close();
    }
}
use std::os::raw::c_char;

#[link(name = "swe")]
extern "C" {
    /// Version
    pub fn swe_version(s_version: &*mut [c_char; 255]) -> *mut [c_char; 255];
    /// Free memory
    pub fn swe_close();
}

But I can't find a way to puti the variable "version" in a CStr or CString...

In debugger I have this in version after raw::swe_version(&version)

version: <invalid adress>
[0]: <read memory from 0x38302e32 failed (0 of 1 bytes read)>
[1]: <read memory from 0x38302e33 failed (0 of 1 bytes read)>
[2]: <read memory from 0x38302e34 failed (0 of 1 bytes read)>
[3]: <read memory from 0x38302e35 failed (0 of 1 bytes read)>
and ... the same until [255]

With your solution rodrigo

use std::ffi::CStr;
mod raw;
pub fn test_lib() {
    let mut version = [0; 255];
    let v = unsafe {
        let p = version.as_mut_ptr();
        raw::swe_version(p);
        CStr::from_ptr(p)
    };
}

I have an error on line:

raw::swe_version(p)

With this in my editor:

1 src/lib.rs|13 col 26 error| mismatched types expected array of 255 elements, found integer note: expected type *mut [i8; 255] found type *mut {integer} [E0308]

1
The documentation of the function says you must pass it a 255 bytes string. You pass it a 1 byte string.mcarton

1 Answers

1
votes

The documentation says that you need an array of 255 characters, so declare just that. And since you are going to change those chars do not forget to add mut:

let mut version = [0; 255];

Then you can use slice::as_mut_ptr() to get the raw pointer and call the external function:

unsafe {
    swe_version(version.as_mut_ptr());
}

Being a C function, probably it will fill the array with a NUL-terminated string. If that is the case, you can get that easily using CStr::from_ptr():

let mut version = [0; 255];
let version = unsafe {
    let p = version.as_mut_ptr();
    swe_version(p);
    std::ffi::CStr::from_ptr(p)
};