AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdint.h>6 7/* Globals for each test */8static sqlite3 *gDb = NULL;9#ifndef SQLITE_OMIT_LOOKASIDE10static void *gLookBuf = NULL;11static const int gLookSlotSize = 128; /* reasonable default slot size */12static const int gLookSlotCount = 32; /* number of slots in lookaside */13#endif14 15void setUp(void) {16 int rc = sqlite3_open(":memory:", &gDb);17 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);18 19#ifndef SQLITE_OMIT_LOOKASIDE20 /* Provide our own lookaside buffer so we control size/count deterministically */21 gLookBuf = sqlite3_malloc(gLookSlotSize * gLookSlotCount);22 TEST_ASSERT_NOT_NULL(gLookBuf);23 rc = sqlite3_db_config(gDb, SQLITE_DBCONFIG_LOOKASIDE,24 gLookBuf, gLookSlotSize, gLookSlotCount);25 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);26#endif27}28 29void tearDown(void) {30#ifndef SQLITE_OMIT_LOOKASIDE31 if( gLookBuf ){32 sqlite3_free(gLookBuf);33 gLookBuf = NULL;34 }35#endif36 if( gDb ){37 int rc = sqlite3_close(gDb);38 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);39 gDb = NULL;40 }41}42 43#ifndef SQLITE_OMIT_LOOKASIDE44static int hold_db_mutex(sqlite3 *db){45 if( db && db->mutex ) sqlite3_mutex_enter(db->mutex);46 return 1;47}48static void release_db_mutex(sqlite3 *db){49 if( db && db->mutex ) sqlite3_mutex_leave(db->mutex);50}51#endif52 53/* Test 1: Freeing a lookaside allocation returns it to the freelist (LIFO) */54#ifndef SQLITE_OMIT_LOOKASIDE55void test_sqlite3DbFreeNN_lookaside_roundtrip(void){56 TEST_ASSERT_NOT_NULL(gDb);57 /* Ensure lookaside is enabled and sized */58 TEST_ASSERT_TRUE(gDb->lookaside.sz > 0);59 TEST_ASSERT_TRUE(gDb->lookaside.bDisable == 0);60 61 hold_db_mutex(gDb);62 63 /* Pick a size that will definitely use lookaside: n <= db->lookaside.sz */64 int n = gDb->lookaside.sz;65 if( n <= 0 ) n = 1;66 if( n > 8 ) n = n/2 + 1; /* a valid, non-trivial size within lookaside */67 68 void *pA = sqlite3DbMallocRawNN(gDb, (u64)n);69 TEST_ASSERT_NOT_NULL(pA);70 void *pB = sqlite3DbMallocRawNN(gDb, (u64)n);71 TEST_ASSERT_NOT_NULL(pB);72 73 /* Free the most recent allocation and expect LIFO reuse on the next alloc */74 sqlite3DbFreeNN(gDb, pB);75 void *q = sqlite3DbMallocRawNN(gDb, (u64)n);76 TEST_ASSERT_EQUAL_PTR(pB, q);77 78 /* Free the remaining lookaside allocations */79 sqlite3DbFreeNN(gDb, pA);80 sqlite3DbFreeNN(gDb, q);81 82 /* Verify that pnBytesFreed does NOT change when freeing lookaside */83 size_t counter = 0;84 gDb->pnBytesFreed = &counter;85 void *pC = sqlite3DbMallocRawNN(gDb, (u64)n);86 TEST_ASSERT_NOT_NULL(pC);87 sqlite3DbFreeNN(gDb, pC); /* lookaside free should not increment counter */88 TEST_ASSERT_EQUAL_UINT64(0, (sqlite3_uint64)counter);89 gDb->pnBytesFreed = 0; /* reset to satisfy future allocations' assert */90 91 release_db_mutex(gDb);92}93#endif94 95/* Test 2: Heap pointer path increments pnBytesFreed and does not free */96void test_sqlite3DbFreeNN_heap_measures_and_late_free(void){97 TEST_ASSERT_NOT_NULL(gDb);98 99 /* Choose a size that forces heap allocation (n > lookaside.sz),100 ** or a reasonable size if lookaside is omitted/disabled. */101 int nHeap = 256;102#ifndef SQLITE_OMIT_LOOKASIDE103 if( gDb->lookaside.sz > 0 ) nHeap = gDb->lookaside.sz + 64;104#endif105 106 if( gDb->mutex ) sqlite3_mutex_enter(gDb->mutex);107 108 /* Allocate from heap via sqlite3DbMallocRawNN */109 void *p = sqlite3DbMallocRawNN(gDb, (u64)nHeap);110 TEST_ASSERT_NOT_NULL(p);111 112 /* Determine the size as sqlite3DbFreeNN would measure it */113 int sz = sqlite3DbMallocSize(gDb, p);114 TEST_ASSERT_TRUE(sz > 0);115 116 /* Set pnBytesFreed and call sqlite3DbFreeNN: should only count, not free */117 size_t counter = 0;118 gDb->pnBytesFreed = &counter;119 sqlite3DbFreeNN(gDb, p);120 TEST_ASSERT_EQUAL_UINT64((sqlite3_uint64)sz, (sqlite3_uint64)counter);121 122 /* Now actually free it by clearing pnBytesFreed and calling again */123 gDb->pnBytesFreed = 0;124 sqlite3DbFreeNN(gDb, p);125 126 if( gDb->mutex ) sqlite3_mutex_leave(gDb->mutex);127}128 129/* Test 3: Heap pointer freed normally when pnBytesFreed is NULL */130void test_sqlite3DbFreeNN_heap_plain_free(void){131 TEST_ASSERT_NOT_NULL(gDb);132 133 int nHeap = 512;134#ifndef SQLITE_OMIT_LOOKASIDE135 if( gDb->lookaside.sz > 0 ) nHeap = gDb->lookaside.sz + 128;136#endif137 138 if( gDb->mutex ) sqlite3_mutex_enter(gDb->mutex);139 140 void *p = sqlite3DbMallocRawNN(gDb, (u64)nHeap);141 TEST_ASSERT_NOT_NULL(p);142 143 /* Ensure pnBytesFreed is not set (normal free) */144 gDb->pnBytesFreed = 0;145 sqlite3DbFreeNN(gDb, p);146 147 if( gDb->mutex ) sqlite3_mutex_leave(gDb->mutex);148}149 150int main(void) {151 UNITY_BEGIN();152#ifndef SQLITE_OMIT_LOOKASIDE153 RUN_TEST(test_sqlite3DbFreeNN_lookaside_roundtrip);154#endif155 RUN_TEST(test_sqlite3DbFreeNN_heap_measures_and_late_free);156 RUN_TEST(test_sqlite3DbFreeNN_heap_plain_free);157 return UNITY_END();158}