LAPACK头文件与MKL库参数不兼容,为何程序未崩溃?
LAPACK与Intel MKL兼容问题:额外参数调用无崩溃的原因分析
问题背景
在两台机器上构建大学项目时,遇到了LAPACK与Intel MKL的兼容问题。排查后发现,问题根源是liblapacke-devel头文件的版本差异:
- 容器环境使用的3.10.0-2ubuntu1版本中,
dsyev这类LAPACK函数的参数列表末尾多了两个和Fortran起源相关的size_t参数,由宏自动添加; - 主机环境使用的3.9.0-1build1版本则没有这两个额外参数。
由于实际链接的是Intel MKL库,而MKL的头文件中dsyev的定义始终没有这两个额外参数,改用MKL头文件后问题解决。
核心疑问
我好奇地尝试用带额外参数的方式调用dsyev(仍链接MKL库,其实现并没有这两个参数),原本预期会出现段错误或其他运行异常,但测试程序却正常运行。这是什么原因?
推测与后续问题
我推测原因是:额外参数位于参数列表末尾,被调用的MKL版dsyev不会访问这些参数,且函数返回后由调用方负责清理栈空间。如果这个推测成立:
- 这种操作是否安全?
- 是否存在潜在的运行时风险?
- 如何检查调用
dsyev前可能存在的栈错位?
尝试验证的困惑
我试过用objdump和nm工具查看共享库,发现库中只包含符号名,没有参数列表信息;又因为缺乏GDB使用经验,没能提取到有效调试信息。请问该如何验证我的推测是否正确?
各环境头文件代码片段
容器环境(liblapacke-dev 3.10.0-2ubuntu1)的lapack.h
... /* It seems all current Fortran compilers put strlen at end. * Some historical compilers put strlen after the str argument * or make the str argument into a struct. */ #define LAPACK_FORTRAN_STRLEN_END ... #define LAPACK_dsyev_base LAPACK_GLOBAL(dsyev,DSYEV) void LAPACK_dsyev_base( char const* jobz, char const* uplo, lapack_int const* n, double* A, lapack_int const* lda, double* W, double* work, lapack_int const* lwork, lapack_int* info #ifdef LAPACK_FORTRAN_STRLEN_END , size_t, size_t #endif ); #ifdef LAPACK_FORTRAN_STRLEN_END #define LAPACK_dsyev(...) LAPACK_dsyev_base(__VA_ARGS__, 1, 1) #else #define LAPACK_dsyev(...) LAPACK_dsyev_base(__VA_ARGS__) #endif
此版本通过LAPACK_dsyev宏自动为dsyev添加两个额外的size_t参数。
主机环境(liblapacke-dev 3.9.0-1build1)的lapack.h
#define LAPACK_dsyev LAPACK_GLOBAL(dsyev,DSYEV) void LAPACK_dsyev( char const* jobz, char const* uplo, lapack_int const* n, double* A, lapack_int const* lda, double* W, double* work, lapack_int const* lwork, lapack_int* info );
容器环境(Intel OneMKL 2024.2)的mkl_lapack.h
void DSYEV( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW; void dsyev( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW; void dsyev_( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW;
包含大写C风格、C风格、Fortran风格三种接口定义,均无额外参数。
主机环境(Intel OneMKL 2021.1.1)的mkl_lapack.h
void DSYEV( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW; void DSYEV_( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW; void dsyev( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW; void dsyev_( const char* jobz, const char* uplo, const MKL_INT* n, double* a, const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork, MKL_INT* info ) NOTHROW;
包含大写C风格、大写Fortran风格、C风格、Fortran风格四种接口定义,均无额外参数。
内容的提问来源于stack exchange,提问作者Moritz Sigg
相关产品推荐
相关产品推荐

