Andruhon
@Andruhon
Software Developer

Как лучше вернуть динамическую строку из Rust через C ABI: extern «C» fn myfunc()?

На первый взгляд можно сделат так, как написано в книжке, однако у меня возникает вопрос каким образом выделяется память под строку в примере? Нужно ли делать free в коде, который эту строку получает? Спрашиваю, поскольку у меня часто в получателе часть строки портилась, особенно если строка была длинной (быть может и дефект на nightly).

Я пришел к какому-то такому устойчиво работающему решению, но оно как-то странно выглядит:
(место под out выделено в C коде, который вызывает эту функцию)
#[no_mangle]
pub extern fn rs_string_in_string_out(s_raw: *const c_char, out: *mut c_char) -> c_int {
    // take string from the input C string
    if s_raw.is_null() { return 0; }

    let c_str: &CStr = unsafe { CStr::from_ptr(s_raw) };
    let buf: &[u8] = c_str.to_bytes();
    let str_slice: &str = std::str::from_utf8(buf).unwrap();
    let str_buf: String = str_slice.to_owned();

    //produce a new string
    let result = String::from(str_buf + " append from Rust");
    let len = result.len();

    //create C string for output
    let c_result = CString::new(result);

    //write string into out pointer passed by C++ addon
    unsafe{ std::ptr::copy(c_result.unwrap().as_ptr(), out, len); };

    // return result length
    return len as c_int;
}
  • Вопрос задан
  • 200 просмотров
Решения вопроса 1
Andruhon
@Andruhon Автор вопроса
Software Developer
Не знаю, насколько это новое, но документация говорит, что библиотеки по умолчанию используют alloc_system, а это значит, что мы можем свободно использовать free в C/C++.
Также, для успокоения совести можно добавить #![feature(alloc_system)] в начало файла.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Сразу скажу, я пока rust только изучаю...
Решение ваше подозрительно только в том, что вы в раст не передаёте размер выделенного в си-коде буфера, на который указывает out. Если строка s_raw получится слишком длинной, то при копировании результата в out может произойти запись за пределы буфера. Поэтому к параметру out нужно ещё передавать размер памяти, на которую он указывает. Т.е. если len будет больше, чем размер памяти, адресуемой out, жди беды.
Пример из книжки работает только потому, что возвращается указатель на строковый литерал — память для него после выхода из hello_rust не освобождается. Если возвращать указатель на переменную, выделенную в раст, память освободится и в Си коде можно получить уже непредсказуемый мусор.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы