ODBC的程序崩溃了

wtogether 2007-06-03 10:49:07
框架搭完了,发现ODBC连接时崩溃了,跟踪一下,就是崩溃在SQLDriverConnect API里,错误日志:
错误应用程序 test.exe,版本 0.0.0.0,错误模块 ole32.dll,版本 5.2.3790.2492,错误地址 0x0001f202。

因为ODBC API我再次封装了的,总是担心内存泄露,所以每声明个内存,先把释放内存的语句写好再写其他代码,谁知道搞了一天的内存检查,发现没内存泄露,于是写了一个纯ODBC的代码进行测试,发现也崩溃了,真是找不到北了,源代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <sqlext.h>

void dbTest()
{
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT stmt = SQL_NULL_HSTMT;
SQLRETURN ret = 0;
SQLINTEGER lngId, lngTime, lngLength;
SQLCHAR strTitle[255] = {0};
ret = SQLSetEnvAttr(SQL_NULL_HENV, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_DRIVER, 0);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)15, 0);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLDriverConnect(hdbc, 0, "Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\\test.mdb", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt);
if (!SQL_SUCCEEDED(ret)) return;
ret = SQLExecDirect(stmt, "SELECT TOP 10 SEQID,TITLE,INTIME FROM ARTICLE", SQL_NTS);
if (!SQL_SUCCEEDED(ret)) return;
while (SQL_SUCCEEDED(SQLFetch(stmt)))
{
SQLGetData(stmt, 1, SQL_C_LONG, &lngId, 0, &lngLength);
SQLGetData(stmt, 1, SQL_C_CHAR, &strTitle, sizeof(strTitle) - 1, &lngLength);
SQLGetData(stmt, 3, SQL_C_LONG, &lngTime, 0, &lngLength);
printf("%ld,%s,%ld\r\n", lngId, strTitle, lngTime);
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}

int main(int argc, char *argv[])
{
dbTest();
return 0;
}

Debug模式编译成test.exe
然后在Debug目录下创建一个:test.bat
call test.exe
test.bat

让程序无限循环,运行还没一分钟,弹出提示,地址不能读
...全文
584 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
wtogether 2007-06-05
  • 打赏
  • 举报
回复
谢谢各位了,可以确定就是连接池的问题了,但是为什么有连接池设置的单线程程序多次运行会造成程序崩溃,确没有这方面的答案了,程序崩溃后,反馈已经发还给微软,不知道他们会不会注意这个问题
wtogether 2007-06-04
  • 打赏
  • 举报
回复
用drwtsn32捕获了错误,崩溃的地方是ole32!CoInitializeSecurity,日志如下:

*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\ole32.dll -
函数: ole32!CoInitializeSecurity
774cf1e4 0064a118 add [ecx+0x18],ah
774cf1e8 0000 add [eax],al
774cf1ea 008b80800f00 add [ebx+0xf8080],cl
774cf1f0 00f6 add dh,dh
774cf1f2 40 inc eax
774cf1f3 0c80 or al,0x80
774cf1f5 0f849174ffff je ole32!CoDisableCallCancellation+0x123 (774c668c)
774cf1fb 8b4640 mov eax,[esi+0x40]
774cf1fe 53 push ebx
774cf1ff 894638 mov [esi+0x38],eax
错误 ->774cf202 8b4860 mov ecx,[eax+0x60] ds:0023:00000060=????????
774cf205 6870034f77 push 0x774f0370
774cf20a 894e48 mov [esi+0x48],ecx
774cf20d 8b4064 mov eax,[eax+0x64]
774cf210 6898030000 push 0x398
774cf215 bbc8095d77 mov ebx,0x775d09c8
774cf21a 685c044f77 push 0x774f045c
774cf21f 8bcb mov ecx,ebx
774cf221 89464c mov [esi+0x4c],eax
774cf224 e816910200 call ole32!OleGetClipboard+0x30f5 (774f833f)
774cf229 8bcf mov ecx,edi

从函数字面上理解,应该就是初始化安全的时候出错了,这个安全应该在哪个位置设置呢?
huashizhixin 2007-06-04
  • 打赏
  • 举报
回复
可能和系统服务设置有关
wtogether 2007-06-04
  • 打赏
  • 举报
回复
to jiangsheng(蒋晟.Net[MVP]) /huashizhixin()
不是return的问题,这只是个测试,原来代码里,return是个错误捕获,!SQL_SUCCEEDED,就输出异常,释放资源,最后才return,代码太长就没贴了,每个API前我都设置了一个日志记录henv/hdbc/hstmt的值,不然我不会知道是否创建了操作以及它崩溃在哪一步

种种错误都考虑到了,例如:
1、Access不支持频繁连接,就用SQL Server,但是异常仍然存在,ole32.dll是个C0000005访问侵犯的错误,我跟踪了henv/hdbc/hstmt,其值都不是0,没什么空指针可言;
2、是Mcafee在检测运行文件,造成了访问侵犯,所以调试时连Mcafee也关了,但还是有异常
3、系统问题,于是换了XP测试,运行10分钟都没崩溃(我自己用的系统是windows 2003),然后又用另外一台2003的,就崩溃,难道真是系统问题?
spofmy 2007-06-04
  • 打赏
  • 举报
回复
顶一下
huashizhixin 2007-06-04
  • 打赏
  • 举报
回复
第三个和第四个if判断改为:
if (!SQL_SUCCEEDED(ret))
{
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return;
}

第五个,六,七个if判断改为:
if (!SQL_SUCCEEDED(ret))
{
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
  SQLFreeHandle(SQL_HANDLE_ENV, henv);
return;
}
第八个if改为:
  if (!SQL_SUCCEEDED(ret))
{
   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return;
}
蒋晟 2007-06-04
  • 打赏
  • 举报
回复
return之前要释放资源
不想写太多层If的话,用构造函数、析构函数来分配、释放资源,或者用do-while(false)+break
spofmy 2007-06-04
  • 打赏
  • 举报
回复
再顶一下
dai_weitao 2007-06-04
  • 打赏
  • 举报
回复
ODBC不会, 帮你顶了
lidongri 2007-06-04
  • 打赏
  • 举报
回复
貌似应该加上异常处理吧。
你试一下
lovesnow1314 2007-06-04
  • 打赏
  • 举报
回复
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);

这三个释放资源的地方,在某些条件下根本不能运行到这里。
所以必须在每一次return 前,都要做这些操作。
wtogether 2007-06-04
  • 打赏
  • 举报
回复
ODBC API 之不可思议、无法理喻

最终解决方法是不使用连接池就一切OK,以防万一,我经过五次测试:

测试1/2:ret = SQLSetEnvAttr(SQL_NULL_HENV, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_DRIVER, 0);//分别连接Access和SQL Server

测试3/4:ret = SQLSetEnvAttr(SQL_NULL_HENV, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_HENV, 0);//分别连接Access和SQL Server

测试5:把连接池设置去掉

测试5运行了半个小时没有崩溃,测试1-4在1分钟内都崩溃了,在官方文档里没看到有这个特别说明,可能2003不兼容ODBC连接池,我还特意在ODBC管理器里打开了Microsoft Access Driver (*.mdb)的连接池,没连接池就麻烦了,并发连接时,独立连接肯定应付不过来的

69,370

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧