#include "sqliteInt.h" #include "unity.h" #include #include /* Wrapper for the static function provided by the build system */ extern void test_renameTokenCheckAll(Parse *pParse, const void *pPtr); static void initParse(sqlite3 **ppDb, Parse *pParse){ sqlite3 *db = 0; int rc = sqlite3_open(":memory:", &db); TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); memset(pParse, 0, sizeof(*pParse)); pParse->db = db; db->pParse = pParse; pParse->nErr = 0; db->mallocFailed = 0; pParse->pRename = 0; *ppDb = db; } static u8* allocByte(u8 val){ u8 *p = (u8*)sqlite3_malloc(1); TEST_ASSERT_NOT_NULL(p); *p = val; return p; } static RenameToken* allocToken(void *pPtr, RenameToken *pNext){ RenameToken *t = (RenameToken*)sqlite3_malloc(sizeof(RenameToken)); TEST_ASSERT_NOT_NULL(t); memset(t, 0, sizeof(*t)); t->p = pPtr; t->pNext = pNext; return t; } static void freeTokenList(RenameToken *p){ while(p){ RenameToken *n = p->pNext; sqlite3_free(p); p = n; } } void setUp(void) { /* no-op */ } void tearDown(void) { /* no-op */ } /* 1) Handles empty rename-token list with nErr==0 and mallocFailed==0 */ void test_renameTokenCheckAll_empty_list(void){ sqlite3 *db = 0; Parse parse; initParse(&db, &parse); /* pRename is NULL by init. Provide a pointer not present in list. */ u8 *other = allocByte(0xAB); test_renameTokenCheckAll(&parse, other); sqlite3_free(other); sqlite3_close(db); } /* 2) Walks multi-node list and safely dereferences each non-NULL p */ void test_renameTokenCheckAll_multi_node_valid_pointers(void){ sqlite3 *db = 0; Parse parse; initParse(&db, &parse); u8 *a = allocByte(0x11); u8 *b = allocByte(0x22); u8 *c = allocByte(0x33); u8 *other = allocByte(0x44); /* pPtr not present in the list */ RenameToken *t3 = allocToken(c, NULL); RenameToken *t2 = allocToken(b, t3); RenameToken *t1 = allocToken(a, t2); parse.pRename = t1; test_renameTokenCheckAll(&parse, other); sqlite3_free(other); sqlite3_free(a); sqlite3_free(b); sqlite3_free(c); freeTokenList(t1); sqlite3_close(db); } /* 3) List contains some tokens with p==NULL; these should be skipped */ void test_renameTokenCheckAll_mixed_null_and_nonnull_pointers(void){ sqlite3 *db = 0; Parse parse; initParse(&db, &parse); u8 *x = allocByte(0x5A); u8 *y = allocByte(0xC3); u8 *other = allocByte(0x7E); /* pPtr not present */ RenameToken *t4 = allocToken(y, NULL); /* non-NULL p */ RenameToken *t3 = allocToken(NULL, t4); /* NULL p -> should be skipped */ RenameToken *t2 = allocToken(x, t3); /* non-NULL p */ RenameToken *t1 = allocToken(NULL, t2); /* NULL p at head */ parse.pRename = t1; test_renameTokenCheckAll(&parse, other); sqlite3_free(other); sqlite3_free(x); sqlite3_free(y); freeTokenList(t1); sqlite3_close(db); } /* 4) When nErr!=0, nothing is dereferenced (even if mallocFailed!=0). Put an invalid/freed pointer in the list to ensure no deref occurs. */ void test_renameTokenCheckAll_nErr_nonzero_avoids_dereference(void){ sqlite3 *db = 0; Parse parse; initParse(&db, &parse); /* Create a pointer and free it to simulate an invalid pointer in list */ u8 *dead = allocByte(0xAA); sqlite3_free(dead); RenameToken *t1 = allocToken(dead, NULL); parse.pRename = t1; /* Set state to bypass the traversal/dereference branch */ parse.nErr = 1; parse.db->mallocFailed = 1; /* This combo is permitted by the assert */ /* pPtr can be anything, including equal to dead; it won't be checked */ test_renameTokenCheckAll(&parse, dead); freeTokenList(t1); sqlite3_close(db); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_renameTokenCheckAll_empty_list); RUN_TEST(test_renameTokenCheckAll_multi_node_valid_pointers); RUN_TEST(test_renameTokenCheckAll_mixed_null_and_nonnull_pointers); RUN_TEST(test_renameTokenCheckAll_nErr_nonzero_avoids_dereference); return UNITY_END(); }