将数据复制到 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 的任何帮助,我们将不胜感激。
我试过了:
- 改用
std::ptr::copy
(我不希望源和目标内存重叠),但仍然出现相同的 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]>(),
);
}
}
我正在尝试移植 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 的任何帮助,我们将不胜感激。
我试过了:
- 改用
std::ptr::copy
(我不希望源和目标内存重叠),但仍然出现相同的 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]>(),
);
}
}