I'm trying to create a dynamic library in Rust that exports a struct as a symbol that will be loaded into a C program via dlopen().
However, I'm was running into some segfaults when accessing the second string in the struct, so I made a small test program to try figure out what I'm doing wrong.
This is the Rust code (test.rs), compiled with "rustc --crate-type dylib test.rs":
#[repr(C)]
pub struct PluginDesc {
name: &'static str,
version: &'static str,
description: &'static str
}
#[no_mangle]
pub static PLUGIN_DESC: PluginDesc = PluginDesc {
name: "Test Plugin\0",
version: "1.0\0",
description: "Test Rust Plugin\0"
};
and here is the C program that attempts to load the library (test.c), compiled with "gcc test.c -ldl -o test":
#include <dlfcn.h>
#include <stdio.h>
typedef struct {
const char *name;
const char *version;
const char *description;
} plugin_desc;
int main(int argc, char **argv) {
void *handle;
plugin_desc *desc;
handle = dlopen("./libtest.so", RTLD_LOCAL | RTLD_LAZY);
if (!handle) {
printf("failed to dlopen: %s\n", dlerror());
return 1;
}
desc = (plugin_desc *) dlsym(handle, "PLUGIN_DESC");
if (!desc) {
printf("failed to dlsym: %s\n", dlerror());
return 1;
}
printf("name: %p\n", desc->name);
printf("version: %p\n", desc->version);
printf("description: %p\n", desc->description);
return 0;
}
This is the output:
name: 0x7fa59ef8d750
version: 0xc
description: 0x7fa59ef8d75c
As you can see, the address of desc->version is actually 0xc (12), which is the length of the first string. So it looks like the struct that gets packed into the library also contains the string length after the memory address.
Am I using the wrong string type here? As you can see I had to also make the strings NULL terminated manually. I tried to use the CString wrapper but that does not seem to work in this case ("static items are not allowed to have destructors").
I'm running the latest Rust nightly on Linux:
$ rustc --version
rustc 0.12.0-pre-nightly (f8426e2e2 2014-09-16 02:26:01 +0000)