将数据复制到 bgfx 中的瞬态顶点缓冲区导致 SIGSEGV

Copying data to transient vertex buffer in bgfx causing SIGSEGV

我正在尝试移植 bgfx application I wrote in C++ to Rust using bgfx-rs。一切正常,直到我尝试将一些顶点数据从应用程序复制到瞬态顶点缓冲区。

let vertices: [f32; 16] = [
    0.0f32,    0.0f32,    0.0f32,    0.0f32,
    1024.0f32, 0.0f32,    1024.0f32, 0.0f32,
    0.0f32,    1024.0f32, 0.0f32,    1024.0f32,
    1024.0f32, 1024.0f32, 1024.0f32, 1024.0f32,
];
let builder = bgfx::VertexLayoutBuilder::new();
builder.begin(RendererType::Noop);
builder.add(
    bgfx::Attrib::Position,
    2,
    bgfx::AttribType::Float,
    bgfx_rs::static_lib::AddArgs {
        normalized: false,
        as_int: false,
    },
);
builder.add(
    bgfx::Attrib::TexCoord0,
    2,
    bgfx::AttribType::Float,
    bgfx_rs::static_lib::AddArgs {
        normalized: false,
        as_int: false,
    },
);
builder.end();
let mut tvb = bgfx::TransientVertexBuffer::new();
if bgfx::get_avail_transient_vertex_buffer(4, &builder) == 4 {
    bgfx::alloc_transient_vertex_buffer(&mut tvb, 4, &builder);
    unsafe {
        let mut data = *tvb.data;
        std::ptr::copy_nonoverlapping(
            vertices.as_ptr() as *const u8,
            &mut data,
            std::mem::size_of::<[f32; 16]>(),
        ); //this line causes SIGSEGV
    }
}

当我添加此 std::ptr::copy_nonoverlapping 操作时,程序因 SIGSEGV 信号而崩溃。

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) 

调试 SIGSEGV 信号原因的最佳方法是什么?我已经尝试 运行 使用 GDB 的代码,但是在崩溃发生之前,根本看不到原因的指示(我可以单步执行信号处理程序,但没有关于崩溃的其他信息)。如果我复制更少的字节(std::mem::size_of::<[f32; 16]>() 解析为 64 字节;即如果我只复制 32 字节)应用程序不会崩溃(但显然我的一些顶点数据丢失了)。

我正在使用不安全块,因为这是让我的 C++ 代码与借用检查器作斗争的唯一方法。供参考我在 C++ 中的代码(工作正常):

const float vertices[16] = {
  0.0f, 0.0f, 0.0f, 0.0f,
  1024.0f, 0.0f, 1024.0f, 0.0f,
  0.0f, 1024.0f, 0.0f, 1024.0f,
  1024.0f, 1024.0f, 1024.0f, 1024.0f
};
ms_decl // bgfx::VertexLayout
  .begin()
  .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
  .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
  .end();
bgfx::TransientVertexBuffer tvb;
if (bgfx::getAvailTransientVertexBuffer(4, ms_decl) == 4) {
  bgfx::allocTransientVertexBuffer(&tvb, 4,ms_decl);
  bx::memCopy(tvb.data, vertices, 16 * sizeof(float));
}

我必须在 Rust 版本中使用 std::ptr::copy_nonoverlapping 的原因是 tvb.data 是 C++ 中的 uint8_t* (reference), while it is const u8* in Rust (reference).

如果我的不安全块有问题或如何深入 SIGSEGV 的任何帮助,我们将不胜感激。

我试过了:

假设我正在读取正确的 documentation,问题是您正在复制到堆栈而不是数据指针。由于 tvb.data*mut u8,调用 let mut data = *tvb.data; 取消引用指针并将值复制到堆栈,这意味着 data 的类型是 u8。然后在ptr::copy_nonoverlapping中引用data得到写入位置。然而,由于 data 现在是堆栈上的一个字节并且几乎不足以容纳复制的值,因此 copy_nonoverlapping 覆盖堆栈上的大量内容导致段错误。

解决方案只是在将 tvb.data 传递给 copy_nonoverlapping 之前将其转换为可变指针。原始指针可能会稍微破坏可变性规则,因为无论哪种方式读取它们都是不安全的。

let mut tvb = bgfx::TransientVertexBuffer::new();
if bgfx::get_avail_transient_vertex_buffer(4, &builder) == 4 {
    bgfx::alloc_transient_vertex_buffer(&mut tvb, 4, &builder);
    unsafe {
        std::ptr::copy_nonoverlapping(
            &vertices as *const u8,
            tvb.data as *mut u8,
            std::mem::size_of::<[f32; 16]>(),
        );
    }
}