1 现象:问题描述
某局点平台版本升级后,调用dll进行号码验证总走失败出口。
2 关键过程:根本原因分析
系统构架描述:
业务运行于平台上,业务由业务人员编写,它给出动态库名、函数名及参数列表,告诉平台如何调用动态库。平台通过LoadLibrary/GetProcAddress加载动态库并调用相应函数。
问题原因描述:
由于动态库中有一些默认参数,因而业务人员编写的业务中告诉平台以下面的接口调用函数:
GetDBRecordFields(int,int,int,int,int,char*,char*)
实际上dll提供的接口函数如下:
int GetDBRecordFields(const int iHandle, const int nRowID, const int nStartColID,
const int nColCount, const int nSize,
char *pszParam1 = NULL,char *pszParam2 = NULL,
char *pszParam3 = NULL,char *pszParam4 = NULL,
char *pszParam5 = NULL,char *pszParam6 = NULL,
char *pszParam7 = NULL,char *pszParam8 = NULL,
char *pszParam9 = NULL,char *pszParam10 = NULL);
由于使用的是C函数调用方式,使用LoadLibrary/GetProcAddress调用函数时,由调用方(即平台程序)压栈,退栈时由被调用方(即动态库函数)退栈。平台调用动态库时,编译器按指定的参数个数(7个参数)进行压栈,但函数退出时,动态库按自身定义的参数个数退栈(15个参数)不正确,导致退栈太多,程序继续运行由于变量不受栈的保护而被覆盖,最终导致异常。
3 结论:解决方案及效果
修改业务,让其调用的dll方式与dll提供的接口一致,问题解决。
4 经验总结:预防措施和规范建议
使用LoadLibrary/ GetProcAddress(在Unix下是dlopen、dlsym函数)调用动态库是很灵活的,但实际应用时要注意:如果提供的动态库接口与实际调用不一致,往往会造成程序的异常行为。实际应用时要注意检查。
5 备注
NA
6 考核点
动态加载与调用动态库,调用时应注意与动态库函数接口一致。
7 试题
动态库中提供了函数:
fun1(char * data, long *len = NULL, long *addr = NULL)
如果在程序中使用动态加载方式调用函数,
并假设函数指针myFunc一定会指向正确的地址,以下调用正确的是(A)
A.
typedef void ( WINAPI *USER1_FUNC)(char * data, long *len , long *addr);
USER1_FUNC myFunc;
myFunc = (USER1_FUNC)::GetProcAddress( hDllModule, "fun1");
myFunc("a string" , NULL , NULL)
B.
typedef void ( WINAPI *USER1_FUNC)(char * data, long *len);
USER1_FUNC myFunc;
myFunc = (USER1_FUNC)::GetProcAddress( hDllModule , "fun1");
myFunc("a string", NULL)
C.
typedef void ( WINAPI *USER1_FUNC)(char * data);
USER1_FUNC myFunc;
myFunc = (USER1_FUNC)::GetProcAddress( hDllModule , "fun1");
myFunc("a string")
阅读(675) | 评论(0) | 转发(0) |