2013-03-28 1 views
0

Je reçois cette erreur en essayant de lancer mon application, j'ai isolé le problème à cette fonction de code, mais je ne comprends pas pourquoi ce qui se passe ...Échec de vérification de l'exécution # 2 - La pile autour de la variable 'db' était corrompue. C++ (Aide)

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); 
     } 
    } 

} 
+0

Pourriez-vous fournir un test complet? – qdii

+0

Avez-vous encore cette erreur si vous commentez 'sqlite3_free (zErrMsg);' – qdii

+0

En note, vous n'avez jamais libéré le 'zErrMsg' passé à ** second ** sqlite3_exec, vous avez donc une fuite de mémoire là-bas. – qdii

Répondre

1

Serait-il possible que vous surchargiez certains tampons char/WCHAR?

Je vous suggère de moderniser votre code et en utilisant classes de cordes robustes, comme std::wstring ou CString[W] avec leurs surcharges de l'opérateur, au lieu de tableaux premières et de chaîne premières C comme wcscat_s() (qui vous utilisent à mauvais escient: vous devez passer _countof(path) au lieu de sizeof(path), car la "taille" doit être exprimée en WCHAR s, pas en octets).

Et pour convertir de Unicode UTF-16 à ANSI/MBCS vous pouvez utiliser ATL helpers like CW2A au lieu de wcstombs_s().

.: par exemple

// 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); 
    .... 

} 

De plus, vous êtes une fuite de mémoire de chaîne parce que vous ne l'appelez pas sqlite3_free(zErrMsg) après le deuxième appel à sqlite3_exec(). Je suggère d'utiliser le modèle RAII et la puissance des destructeurs C++ pour essayer d'écrire du code que automatiquement libère des ressources. Vous pouvez écrire un emballage simple sur ces chaînes, qui appelle sqlite3_free() dans le destructor, .: par exemple

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; 
}; 

Une enveloppe similaire pourrait être construit autour du pointeur sqlite3*.

+0

J'essaye de rendre ceci aussi léger que possible avec le moins de dépendances. ATL et .net framework est quelque chose que je veux éviter – James

+0

ATL est très utile et très léger (la comparaison avec .NET Framework n'a pas de sens). –

Questions connexes