我用最新的stable版本1.67.1和最新的nightly版本1.69.0编译一个rust项目hola,运行出现了段错误,但把工具链降级到1.66.1版本后编译出来又能正常运行。用gdb对比调试两个版本编译出来的程序,发现区别在于alloc::raw_vec::RawVec<f64, alloc::alloc::Global>::allocate_in<f64, alloc::alloc::Global>
,新版本执行这个函数后内存中数组指针和长度的布局是反过来的,后续代码把长度当作指针用,然后导致段错误了。有没有有经验的大佬知道这是怎么回事?是程序的问题还是编译器的问题?
1
共 11 条评论, 1 页
评论区
写评论这个问题有非常多的解决方法,都是改dlib-face-recognition里的new_from_vec函数。其实这个bug最好的解决方法是直接传vector的指针,然后循环的时候用索引就好了,比如这样。
--
👇
Matheritasiv: 学到了,谢谢前辈!
--
👇
Bai-Jinlin: 像我下面写的那样改saanuregh/dlib-face-recognition库的代码,或者只能锁定rustc的版本依赖这个编译器版本特有的内存布局了,话说这个库都三年没新的提交了
--
👇
Matheritasiv: 那这个问题有没有不依赖编译器版本的解决方案?
--
👇
Bai-Jinlin: 想修复也简单,在new_from_vec的34行下面 https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L34插入代码。
在把下面cpp宏的vector as "dlib::matrix<double,0,1>"里的vector改成hack_vector。说到底就是作者太偷懒了。
👇
Bai-Jinlin: 我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
学到了,谢谢前辈!
--
👇
Bai-Jinlin: 像我下面写的那样改saanuregh/dlib-face-recognition库的代码,或者只能锁定rustc的版本依赖这个编译器版本特有的内存布局了,话说这个库都三年没新的提交了
--
👇
Matheritasiv: 那这个问题有没有不依赖编译器版本的解决方案?
--
👇
Bai-Jinlin: 想修复也简单,在new_from_vec的34行下面 https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L34插入代码。
在把下面cpp宏的vector as "dlib::matrix<double,0,1>"里的vector改成hack_vector。说到底就是作者太偷懒了。
👇
Bai-Jinlin: 我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
像我下面写的那样改saanuregh/dlib-face-recognition库的代码,或者只能锁定rustc的版本依赖这个编译器版本特有的内存布局了,话说这个库都三年没新的提交了
--
👇
Matheritasiv: 那这个问题有没有不依赖编译器版本的解决方案?
--
👇
Bai-Jinlin: 想修复也简单,在new_from_vec的34行下面 https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L34插入代码。
在把下面cpp宏的vector as "dlib::matrix<double,0,1>"里的vector改成hack_vector。说到底就是作者太偷懒了。
👇
Bai-Jinlin: 我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
那这个问题有没有不依赖编译器版本的解决方案?
--
👇
Bai-Jinlin: 想修复也简单,在new_from_vec的34行下面 https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L34插入代码。
在把下面cpp宏的vector as "dlib::matrix<double,0,1>"里的vector改成hack_vector。说到底就是作者太偷懒了。
👇
Bai-Jinlin: 我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
想修复也简单,在new_from_vec的34行下面 https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L34插入代码。
在把下面cpp宏的vector as "dlib::matrix<double,0,1>"里的vector改成hack_vector。说到底就是作者太偷懒了。
👇
Bai-Jinlin: 我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
这是再往前
x.data.clone()
调用完成后的内存布局,可以看到rsi所指向的内存就是长度在前指针在后的,用老版本rust编译出来的程序在这里是指针在前长度在后。--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
我试了下,在最新的nightly确实三个字段的顺序和以前不一致了,但是我认为这不是bug,只是那个程序的作者自己假定了三个字段的顺序导致的,作者假设vec的字段是addr,len,cap这么排布可以直接映射成cpp的matrix类型导致的问题,毕竟这种强制类型转换是unsafe。
--
👇
Matheritasiv: 不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
不是索引的问题,这是发生段错误处的代码: 第89行rbx是0,说明当前是在第一轮循环中,rcx理应是数组指针,但这里成了数组的长度128,根据第64行,它的值来自[r14],但[r14+0x8]处才是数组指针。
👇
Bai-Jinlin: 我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
我看了下代码,我觉得原因大概是这样,FaceEncoding里的new_from_vec函数:https://github.com/saanuregh/dlib-face-recognition/blob/encoding-patch/src/face_encoding/encoding.rs#L33 的cpp宏里的循环用的是size_t。 但是dlib::matrix里的operator()操作符的参数是32位的long:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix.h#L1290。我认为是循环的时候发生了截断导致long为负数,在索引date出现的段错误。 而且这个代码很取巧的把vec直接cast成了matrix里的layout<T,num_rows,num_cols,mem_manager,3>字段的类型,里的指针字段正好可以对上号:https://github.com/davisking/dlib/blob/master/dlib/matrix/matrix_data_layout.h#L356。
安装后首先运行
录入面部数据,再运行
就会出现段错误,出错位置是
src/app.rs
的第200行:向量拷贝后传到C++闭包的过程中。我在
Cargo.toml
里面用的cpp_build
版本是0.5.7
。--
👇
hax10: 我刚在Linux下使用cargo 1.67.1试了一下。编译通过了,程序也能正常运行起来。你cargo clean再cargo build一下试试?
我刚在Linux下使用cargo 1.67.1试了一下。编译通过了,程序也能正常运行起来。你cargo clean再cargo build一下试试?