【问题标题】:C to Rust and back "pointer being freed was not allocated" on Rust sideC 到 Rust 并返回 Rust 端的“未分配指针”
【发布时间】:2018-10-04 16:12:41
【问题描述】:

我正在尝试从 C 中调用一些 Rust 代码并返回结果,但在 Rust 端出现“未分配指针被释放”错误。

我想调用hex::encode 函数。我传入一个指向某些字节的指针、长度和一个在 C 中用 malloc 分配的指针。我希望在这个指针处传回转换的结果。

Rust 函数:

extern crate libc;

use hex;
use std::ffi::CString;
use std::os::raw::c_char;
use std::vec::Vec;
use std::{ffi, ptr, slice};

#[no_mangle]
pub extern "C" fn bytes_to_hex_string(bp: *mut u8, bp_size: usize, sp: *mut c_char) -> i8 {
    println!("1");

    let p_vec = unsafe { Vec::from_raw_parts(bp, bp_size, bp_size + 1) };

    println!("2");

    let str = hex::encode(p_vec);

    println!("3");

    let bytes = str.as_bytes();

    println!("4");

    let cs = CString::new(bytes).unwrap(); // will fail if bytes has "gap" (null) in sequence

    println!("5");

    unsafe {
        libc::strcpy(sp, cs.as_ptr());
    }

    println!("6");

    return 1;
}

从此 C 代码调用:

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

int8_t bytes_to_hex( uint8_t *, unsigned int, char *);

int main() {
  char *ptr = "Hello World!";
  char *hex = (char *)malloc(1000);
  printf("about to call....\n");
  bytes_to_hex_string((uint8_t*)ptr,strlen(ptr),hex); 
  printf("about to print....\n");
  printf("%s\n",hex);
  printf("about to free....\n");
  free(hex);
}

当我运行程序时:

$ ./a.out
about to call....
1
2
a.out(2941,0x7fffccae03c0) malloc: *** error for object 0x10afe2b80: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

看起来 hex crate 中的 Rust 代码正在释放 ptr 指针,对吗?

有没有办法以某种方式解决这个问题?我更希望在 C 中进行分配和释放,但我愿意接受任何解决此问题的建议!

【问题讨论】:

  • 来自Vec::from_raw_parts 上的文档:"ptr 需要先前已通过String/Vec&lt;T&gt; 分配(至少,如果它不是't)." 通常,它旨在用作恢复先前被反汇编/忘记的Vec 的方法,而不是用作从任意内存缓冲区创建向量的方法。正如答案所暗示的,将这些原始部分变成一片很可能是正确的方法。

标签: c rust


【解决方案1】:

如果您不希望 Rust 释放您的指针,请不要使用拥有该分配的类型。 VecCString 都拥有指针的所有权并对其进行管理。想必你很惊讶需要同时提供长度和容量?

改用slice::from_raw_parts

extern crate libc;
extern crate hex;

use std::ffi::CString;
use std::os::raw::c_char;
use std::slice;

#[no_mangle]
pub unsafe extern "C" fn bytes_to_hex_string(bp: *mut u8, bp_size: usize, sp: *mut c_char) -> i8 {
    let p_vec = slice::from_raw_parts(bp, bp_size);

    let str = hex::encode(p_vec);
    let cs = CString::new(str).unwrap();

    libc::strcpy(sp, cs.as_ptr());

    return 1;
}

我没有对此进行测试,所以我不能说您的strcpy 是否正确。然而,FFI 函数中的恐慌是未定义的行为。同样令人惊讶的是,您将两个指针都声明为可变的......您也不需要导入Vec,因为它在前奏中。

另见:

【讨论】:

  • 成功了。正如你所说,我将第一个指针设为 const。我不知道有些类型可以管理,有些则不能。很多东西要学 rust :( 非常感谢。
猜你喜欢
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 2021-07-26
  • 2015-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多