Я создаю привязку к libdpkg
в Rust (в основном, чтобы узнать о Rust FFI), используя rust-bindgen
.
Я столкнулся с проблемой в самом начале реализации.
У меня есть следующий код Rust:
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
use std::convert::TryInto;
use std::ffi::CString;
use std::os::raw::c_char;
pub struct Dpkg {
program_name: *mut c_char,
root_directory: Option<*mut c_char>,
}
impl Dpkg {
pub fn new(program_name: &str, root_directory: Option<&str>) -> Dpkg {
let dpkg = Dpkg {
program_name: CString::new(program_name).unwrap().into_raw(),
root_directory: match root_directory {
Some(dir) => Some(CString::new(dir).unwrap().into_raw()),
None => None,
},
};
unsafe {
dpkg_set_progname(dpkg.program_name);
push_error_context();
if let Some(dir) = dpkg.root_directory {
dpkg_db_set_dir(dir);
}
modstatdb_init();
modstatdb_open(modstatdb_rw_msdbrw_available_readonly);
}
dpkg
}
}
impl Drop for Dpkg {
fn drop(&mut self) {
unsafe {
pkg_db_reset();
modstatdb_done();
modstatdb_shutdown();
pop_error_context(ehflag_normaltidy.try_into().unwrap());
let _ = CString::from_raw(self.program_name);
if let Some(dir) = self.root_directory {
let _ = CString::from_raw(dir);
}
}
}
}
У меня есть следующие интеграционные тесты:
extern crate dpkg;
use dpkg::Dpkg;
use std::mem;
#[test]
fn test_new() {
let dpkg = Dpkg::new("test", None);
mem::drop(dpkg);
let dpkg = Dpkg::new("test2", None);
mem::drop(dpkg);
}
#[test]
fn test_new2() {
let dpkg = Dpkg::new("test", None);
mem::drop(dpkg);
}
В первом тесте, независимо от того, сколько раз я вызываю Dpkg::new()
все в порядке и работает нормально.
Однако, если я выполню Dpkg::new()
в test_new2()
, результатом будет либо segfault, либо следующая ошибка:
test: unrecoverable fatal error, aborting:
parsing file '/var/lib/dpkg/status' near line 10 package 'fonts-sil-abyssinica':
'Replaces' field, invalid package name '�': must start with an alphanumeric character
I'mхотя я не совсем уверен, почему.Следующая программа на C работает, как и ожидалось:
#include <stdio.h>
#define LIBDPKG_VOLATILE_API
#include <dpkg/dpkg-db.h>
#include <dpkg/dpkg.h>
#include <stdlib.h>
void setup_dpkg(const char *program_name, const char *root_directory) {
dpkg_set_progname(program_name);
push_error_context();
if (root_directory != NULL) {
dpkg_db_set_dir(root_directory);
}
modstatdb_init();
modstatdb_open(msdbrw_available_readonly);
}
void destroy_dpkg() {
pkg_db_reset();
modstatdb_done();
pop_error_context(ehflag_normaltidy);
}
int main() {
for (int i =0; i < 100; i++) {
char *program_name = (char*)malloc(32 * sizeof(char));
strcpy(program_name, "test");
char *dir = (char*)malloc(16 * sizeof(char));
strcpy(dir, "/var/lib/dpkg");
setup_dpkg(program_name, dir);
printf("%d time!\n", i);
destroy_dpkg();
free(program_name);
free(dir);
}
return 0;
}
Вывод:
0 time!
1 time!
2 time!
3 time!
4 time!
5 time!
6 time!
7 time!
8 time!
9 time!
10 time!
11 time!
12 time!
13 time!
14 time!
15 time!
16 time!
17 time!
18 time!
19 time!
20 time!
21 time!
22 time!
23 time!
24 time!
25 time!
26 time!
27 time!
28 time!
29 time!
30 time!
31 time!
32 time!
33 time!
34 time!
35 time!
36 time!
37 time!
38 time!
39 time!
40 time!
41 time!
42 time!
43 time!
44 time!
45 time!
46 time!
47 time!
48 time!
49 time!
50 time!
51 time!
52 time!
53 time!
54 time!
55 time!
56 time!
57 time!
58 time!
59 time!
60 time!
61 time!
62 time!
63 time!
64 time!
65 time!
66 time!
67 time!
68 time!
69 time!
70 time!
71 time!
72 time!
73 time!
74 time!
75 time!
76 time!
77 time!
78 time!
79 time!
80 time!
81 time!
82 time!
83 time!
84 time!
85 time!
86 time!
87 time!
88 time!
89 time!
90 time!
91 time!
92 time!
93 time!
94 time!
95 time!
96 time!
97 time!
98 time!
99 time!
Я что-то не так делаю (что вероятно) или это запускает тест Rust, который вызываеттакие проблемы?