Linux下ODBC C++程序SQLConnect时因get_charset_by_csname崩溃排查
Linux环境下ODBC连接TD-SQL时SQLConnect崩溃排查分析
问题描述
- Windows环境中程序可正常通过ODBC连接TD-SQL,但Linux环境下执行
SQLConnect时崩溃,崩溃栈见相关截图 MY_SQL_CHAR在Linux中定义为SQLCHAR,在Windows中定义为SQLWCHAR- 同类代码单独运行无异常,集成到大项目后出现相同崩溃
核心代码
int COdbcConnect::Connect(const char* pDataSource) { LOG_WARNING(g_pLogHandle, "xxxxxxxxxx, pDataSource:%s", pDataSource); ///test3 m_strDataSource = std::string(pDataSource); SQLRETURN ret; if (m_pEnv == NULL) { if (false == initEnv(m_pEnv)) ///test3 { return 1; } } UTIL_Strcpy(m_pEnv->dataSource, MAX_DATA_SOURCE_LENGTH, pDataSource); CloseConnect(); try { ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(m_pEnv->hEnv)); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: when exec SQLAllocHandle",m_pEnv->hEnv,SQL_HANDLE_ENV) SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 2; } ret=SQLSetEnvAttr((m_pEnv->hEnv), SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: when exec SQLAllocHandle",m_pEnv->hEnv,SQL_HANDLE_ENV) SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 3; } ret = SQLAllocHandle(SQL_HANDLE_DBC, m_pEnv->hEnv, &(m_pEnv->hDbc)); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: allocate odbc connection handler",m_pEnv->hEnv,SQL_HANDLE_ENV); SQLFreeHandle(SQL_HANDLE_DBC, m_pEnv->hDbc); SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 4; } LOG_WARNING(g_pLogHandle, "ret = %d, datasource = %p, %s, m_pEnv->hDbc:%p", ret, m_pEnv->dataSource, m_pEnv->dataSource, m_pEnv->hDbc); ///test3 ret=SQLConnect((m_pEnv->hDbc), (MY_SQL_CHAR*)"smarteazy", SQL_NTS, (MY_SQL_CHAR *)NULL, SQL_NTS, (MY_SQL_CHAR *)NULL, SQL_NTS); ///test3 //const char* pAbc = "smarteazy"; //ret=SQLConnect((m_pEnv->hDbc), (MY_SQL_CHAR*)pAbc, // SQL_NTS, (MY_SQL_CHAR *)NULL, SQL_NTS, (MY_SQL_CHAR *)NULL, // SQL_NTS); ///test3 //ret=SQLConnect((env->hDbc), (SQLCHAR*)env->data_source, // SQL_NTS, (SQLCHAR *)NULL, SQL_NTS, (SQLCHAR *)NULL, // SQL_NTS); //LOG_WARNING(g_pLogHandle, "ret = %d, datasource = %s", ret, m_pEnv->dataSource); ///test3 if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { // 连接失败 m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: when exec SQLConnect",m_pEnv->hEnv,SQL_HANDLE_ENV); SQLFreeHandle(SQL_HANDLE_DBC, m_pEnv->hDbc); SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 5; } ret = SQLAllocHandle(SQL_HANDLE_STMT, (m_pEnv->hDbc), &(m_pEnv->hStmt)); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: when exec SQLAllocHandle",m_pEnv->hEnv,SQL_HANDLE_ENV) SQLFreeHandle(SQL_HANDLE_STMT, m_pEnv->hStmt); SQLFreeHandle(SQL_HANDLE_DBC, m_pEnv->hDbc); SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 6; } else { m_bConnected = true; } } catch (char* pError) { LOG_WARNING(g_pLogHandle, "catch exception error:%s", pError); m_bConnected = false; ONLY_CHECK_ERROR(ret,"Connect: when exec SQLAllocHandle",m_pEnv->hEnv,SQL_HANDLE_ENV); SQLFreeHandle(SQL_HANDLE_STMT, m_pEnv->hStmt); SQLFreeHandle(SQL_HANDLE_DBC, m_pEnv->hDbc); SQLFreeHandle(SQL_HANDLE_ENV, m_pEnv->hEnv); return 7; } return 0; }
排查方向
1. 字符编码与类型转换问题
Linux下MY_SQL_CHAR是单字节SQLCHAR,代码中直接将字符串常量"smarteazy"强制转换为MY_SQL_CHAR*,看似兼容,但需注意:
- TD-SQL的Linux ODBC驱动可能要求特定字符集(如UTF-8),大项目中若全局设置了其他编码(如GBK),会导致字符串编码混乱,触发崩溃
- 建议避免直接强制转换,根据
MY_SQL_CHAR类型构造对应字符串:Linux下用SQLCHAR数组存储,Windows下用宽字符串前缀L,或用ODBC标准转换函数统一处理字符集
2. 环境变量与驱动依赖冲突
大项目可能修改了ODBC相关环境变量(如ODBCINI、ODBCSYSINI),导致加载错误的驱动版本,或驱动依赖库与项目其他库冲突:
- 打印大项目启动前后的ODBC环境变量,对比单独运行时的变量值
- 用
ldd命令检查项目可执行文件依赖的ODBC驱动库版本,确认与单独运行时一致
3. 内存管理与缓冲区溢出
- 检查
CloseConnect()实现,确保每次连接前完全释放hEnv、hDbc等ODBC句柄,避免野指针或重复分配 - 验证
UTIL_Strcpy的安全性:若pDataSource长度超过MAX_DATA_SOURCE_LENGTH,会导致缓冲区溢出,破坏m_pEnv的成员结构,大项目内存布局更紧凑,更容易触发崩溃
4. 线程安全问题
大项目多线程环境下,ODBC句柄(尤其是环境句柄hEnv)若未做线程隔离,多线程同时操作会导致崩溃:
- 确认
m_pEnv是否为线程私有数据,或在多线程调用Connect时添加互斥锁保护
5. 编译选项差异
大项目与测试程序的编译选项(优化等级、对齐规则、宏定义)不同,可能导致m_pEnv结构体内存布局变化,引发访问偏移错误:
- 对比两者的编译参数,确保ODBC相关结构体的编译选项一致(如对齐方式、是否开启内存优化)
内容的提问来源于stack exchange,提问作者eric
相关产品推荐
相关产品推荐

