c++ - 运行时检查失败 #2 - 变量 'db' 周围的堆栈已损坏。 c++ (帮助)

标签 c++ winapi visual-studio-2012 sqlite

我在尝试启动我的应用程序时遇到此错误,我已将问题隔离到此代码函数,但我不明白为什么会发生这种情况...

void checkDB()
{
    sqlite3 *db;
    int rc=0;
    size_t i;
    char *zErrMsg = 0;

    HMODULE hModule = GetModuleHandleW(NULL);
    WCHAR path[MAX_PATH];
    char buffer[MAX_PATH*4];
    int len;
    GetModuleFileNameW(hModule, path, MAX_PATH);
    len =lstrlenW(path);
    path[len-13]='\0';
    buffer[0]='\0';

    wcscat_s(path,sizeof(path),L"test.db\0");
    GetFileAttributes(path);
    if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(path) && GetLastError()==ERROR_FILE_NOT_FOUND)
    {
        wcstombs_s(&i,buffer,sizeof(buffer), path, wcslen(path) );
        rc= sqlite3_open(buffer,&db);

        rc=sqlite3_exec(db,"create table Recipe (Recipe_Num INTEGER PRIMARY KEY AUTOINCREMENT, Recipe_Image VARCHAR(30), Recipe_Name VARCHAR(200))",NULL,0,&zErrMsg);
        sqlite3_free(zErrMsg);
        rc=sqlite3_exec(db,"create table Recipe_Step (Recipe_Num INTEGER, Step_Num INTEGER, Description VARCHAR(2000))",NULL,0,&zErrMsg);
        if(rc!=SQLITE_OK)
        {
            sqlite3_close(db);
        }
        else
        {
        sqlite3_close(db);
        }
    }

}

最佳答案

是否有可能您正在溢出一些原始 char/WCHAR 缓冲区?

我建议您使代码现代化并使用健壮的字符串类,例如std::wstringCString[W]运算符重载,而不是像 wcscat_s() 这样的原始数组和原始 C 字符串函数(你误用了:你应该传递 _countof(path) 而不是 sizeof( path),因为“大小”必须用 WCHAR 表示,而不是字节)。

要将 Unicode UTF-16 转换为 ANSI/MBCS,您可以使用 ATL helpers like CW2A而不是 wcstombs_s()

例如:

// Assume Unicode builds, so GetModuleFileName is actually GetModuleFileNameW,
// CString is CStringW, etc.

CString strPath;
WCHAR* pszPath = strPath.GetBuffer(MAX_PATH);
GetModuleFileName(hModule, pszPath, MAX_PATH);
// check GetModuleFileName()'s return value...
strPath.ReleaseBuffer();

// Operate on strPath using operator+= to concatenate strings, etc.
strPath += L"test.db";

....

if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(strPath) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
    // Convert from UTF-16 to ANSI
    CW2A buffer(strPath);
    rc = sqlite3_open(buffer, &db);
    ....

}

此外,您正在泄漏字符串内存,因为您在第二次调用 sqlite3_exec() 后没有调用 sqlite3_free(zErrMsg)。我建议使用 RAII 模式和 C++ 析构函数的强大功能来尝试编写自动释放资源的代码。 您可以在这些字符串上编写一个简单的包装器,在析构函数中调用 sqlite3_free(),例如:

class SqlLiteErrorMsg
{
public:   
    SqlLiteErrorMsg()
       : errorMsg(nullptr)
    {}

    ~SqlLiteErrorMsg()
    {
        sqlite3_free(errorMsg);
    }

    char** GetAddressOf()
    {
        return &errorMsg;
    }    

    char* Get()
    {
        return errorMsg;
    }

private:
    // Ban copy
    SqlLiteErrorMsg(const SqlLiteErrorMsg&);
    SqlLiteErrorMsg& operator=(const SqlLiteErrorMsg&);

    char* errorMsg;
};

可以围绕 sqlite3* 指针构建类似的包装器。

关于c++ - 运行时检查失败 #2 - 变量 'db' 周围的堆栈已损坏。 c++ (帮助),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15689888/

相关文章:

c++ - 什么是 undefined reference /未解析的外部符号错误以及如何修复它?

winapi - 流畅播放实时网络音频样本

c# - ssl 证书代码异常

C# 到 C++ 的转换

c++ - 如何在 Windows Mobile 6 上获得 "busy wheel"?

c++ - CUDA - 将 cpu 代码与 cuda 代码分开

c# - 检查用户何时更改 Windows 玻璃刷(主题颜色)

c++ - 如何在 C++ Win32 应用程序中创建 Windows 风格的文本框

tfs - 使用托管 TFS 将变更集编号转换为版本信息

visual-studio - 商业智能项目是否支持自定义默认模板?