AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6#include <unistd.h>7 8/* Target under test */9void sqlite3MemSetDefault(void);10 11/* Exported memdebug helpers from mem2.c */12void sqlite3MemdebugSetType(void *p, u8 eType);13int sqlite3MemdebugHasType(const void *p, u8 eType);14int sqlite3MemdebugNoType(const void *p, u8 eType);15void sqlite3MemdebugBacktrace(int depth);16void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **));17void sqlite3MemdebugSettitle(const char *zTitle);18void sqlite3MemdebugDump(const char *zFilename);19int sqlite3MemdebugMallocCount(void);20void sqlite3MemdebugSync(void);21 22static volatile int g_btCalled = 0;23static volatile int g_btLastSize = -1;24static volatile int g_btLastDepth = -999;25 26/* Backtrace callback to observe allocator behavior */27static void test_backtrace_cb(int nByte, int nDepth, void **ppFrames){28 (void)ppFrames;29 g_btCalled++;30 g_btLastSize = nByte;31 g_btLastDepth = nDepth;32}33 34void setUp(void) {35 /* Ensure SQLite is shut down so sqlite3_config in sqlite3MemSetDefault is valid */36 sqlite3_shutdown();37 /* Reset backtrace callback state */38 sqlite3MemdebugBacktraceCallback(NULL);39 g_btCalled = 0;40 g_btLastSize = -1;41 g_btLastDepth = -999;42}43 44void tearDown(void) {45 /* Best-effort shutdown of the configured memory subsystem */46 if( sqlite3GlobalConfig.m.xShutdown ){47 sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData);48 }49 sqlite3MemdebugBacktraceCallback(NULL);50}51 52/* Helper to initialize the mem subsystem after configuration */53static void init_mem(void){54 if( sqlite3GlobalConfig.m.xInit ){55 int rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);56 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);57 }58}59 60void test_sqlite3MemSetDefault_sets_methods_nonnull(void) {61 sqlite3MemSetDefault();62 init_mem();63 64 const sqlite3_mem_methods *m = &sqlite3GlobalConfig.m;65 66 TEST_ASSERT_NOT_NULL(m->xMalloc);67 TEST_ASSERT_NOT_NULL(m->xFree);68 TEST_ASSERT_NOT_NULL(m->xRealloc);69 TEST_ASSERT_NOT_NULL(m->xSize);70 TEST_ASSERT_NOT_NULL(m->xRoundup);71 TEST_ASSERT_NOT_NULL(m->xInit);72 TEST_ASSERT_NOT_NULL(m->xShutdown);73 74 /* Roundup behavior */75 TEST_ASSERT_EQUAL_INT(0, m->xRoundup(0));76 TEST_ASSERT_EQUAL_INT(8, m->xRoundup(1));77 TEST_ASSERT_EQUAL_INT(8, m->xRoundup(7));78 TEST_ASSERT_EQUAL_INT(8, m->xRoundup(8));79 TEST_ASSERT_EQUAL_INT(16, m->xRoundup(9));80 TEST_ASSERT_EQUAL_INT(16, m->xRoundup(16));81 TEST_ASSERT_EQUAL_INT(1000 + (8 - (1000 % 8)), m->xRoundup(1000));82}83 84void test_sqlite3MemSetDefault_allocator_basic_alloc_realloc_free_and_size_roundup(void) {85 sqlite3MemSetDefault();86 init_mem();87 88 const sqlite3_mem_methods *m = &sqlite3GlobalConfig.m;89 90 /* Track allocation count difference */91 int n0 = sqlite3MemdebugMallocCount();92 93 /* Allocate 13 bytes, test size reporting */94 unsigned char *p = (unsigned char*)m->xMalloc(13);95 TEST_ASSERT_NOT_NULL(p);96 TEST_ASSERT_EQUAL_INT(13, m->xSize(p));97 98 /* Fill and then realloc to a larger 8-byte aligned size (24) */99 for(int i=0;i<13;i++) p[i] = (unsigned char)i;100 unsigned char *p2 = (unsigned char*)m->xRealloc(p, 24);101 TEST_ASSERT_NOT_NULL(p2);102 /* Old pointer should not be used anymore; content must be preserved */103 for(int i=0;i<13;i++){104 TEST_ASSERT_EQUAL_UINT8((unsigned char)i, p2[i]);105 }106 TEST_ASSERT_EQUAL_INT(24, m->xSize(p2));107 108 m->xFree(p2);109 110 int n1 = sqlite3MemdebugMallocCount();111 TEST_ASSERT_TRUE(n1 >= n0 + 2); /* one for initial alloc and one for realloc's new alloc */112}113 114void test_sqlite3MemSetDefault_memdebug_type_tagging_works(void) {115 sqlite3MemSetDefault();116 init_mem();117 118 const sqlite3_mem_methods *m = &sqlite3GlobalConfig.m;119 120 void *p = m->xMalloc(32);121 TEST_ASSERT_NOT_NULL(p);122 123 /* Initially the mem2 allocator tags allocations as MEMTYPE_HEAP */124 TEST_ASSERT_TRUE(sqlite3MemdebugHasType(p, MEMTYPE_HEAP));125 126 /* Change type to 0, verify it is no longer reported as HEAP */127 sqlite3MemdebugSetType(p, 0);128 TEST_ASSERT_FALSE(sqlite3MemdebugHasType(p, MEMTYPE_HEAP));129 130 /* Set to LOOKASIDE and validate Has/NoType logic */131 sqlite3MemdebugSetType(p, MEMTYPE_LOOKASIDE);132 TEST_ASSERT_TRUE(sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE));133 TEST_ASSERT_TRUE(sqlite3MemdebugNoType(p, MEMTYPE_HEAP));134 135 m->xFree(p);136}137 138void test_sqlite3MemSetDefault_backtrace_callback_invoked(void) {139 sqlite3MemSetDefault();140 init_mem();141 142 const sqlite3_mem_methods *m = &sqlite3GlobalConfig.m;143 144 sqlite3MemdebugBacktrace(3); /* rounded up to 4 by implementation */145 sqlite3MemdebugBacktraceCallback(test_backtrace_cb);146 147 void *p = m->xMalloc(40);148 TEST_ASSERT_NOT_NULL(p);149 150 /* Expect callback called at least once on allocation */151 TEST_ASSERT_TRUE(g_btCalled >= 1);152 TEST_ASSERT_EQUAL_INT(40, g_btLastSize);153 /* Depth is implementation-defined; just ensure it's not some sentinel */154 TEST_ASSERT_NOT_EQUAL_INT(-999, g_btLastDepth);155 156 /* Sync should invoke callback for outstanding allocations */157 int calledBefore = g_btCalled;158 sqlite3MemdebugSync();159 TEST_ASSERT_TRUE(g_btCalled >= calledBefore + 1);160 161 m->xFree(p);162 163 /* Reset callback */164 sqlite3MemdebugBacktraceCallback(NULL);165}166 167static void read_file_into_buffer(const char *zFile, char *buf, size_t bufSize){168 FILE *f = fopen(zFile, "rb");169 TEST_ASSERT_NOT_NULL(f);170 size_t n = fread(buf, 1, bufSize-1, f);171 buf[n] = '\0';172 fclose(f);173}174 175void test_sqlite3MemSetDefault_settitle_reflected_in_dump(void) {176 sqlite3MemSetDefault();177 init_mem();178 179 const sqlite3_mem_methods *m = &sqlite3GlobalConfig.m;180 181 const char *title = "UNIT-TEST-TITLE-XYZ";182 sqlite3MemdebugSettitle(title);183 184 void *p = m->xMalloc(64);185 TEST_ASSERT_NOT_NULL(p);186 187 /* Create a temporary filename for dump */188 char tmpl[] = "/tmp/sqlite_mem2_dump_XXXXXX";189 int fd = mkstemp(tmpl);190 TEST_ASSERT_TRUE(fd >= 0);191 close(fd); /* we will reopen with stdio APIs */192 193 sqlite3MemdebugDump(tmpl);194 195 char buf[8192];196 read_file_into_buffer(tmpl, buf, sizeof(buf));197 /* Our title should appear in the dump */198 TEST_ASSERT_NOT_NULL(strstr(buf, title));199 200 /* Cleanup */201 unlink(tmpl);202 m->xFree(p);203}204 205int main(void) {206 UNITY_BEGIN();207 RUN_TEST(test_sqlite3MemSetDefault_sets_methods_nonnull);208 RUN_TEST(test_sqlite3MemSetDefault_allocator_basic_alloc_realloc_free_and_size_roundup);209 RUN_TEST(test_sqlite3MemSetDefault_memdebug_type_tagging_works);210 RUN_TEST(test_sqlite3MemSetDefault_backtrace_callback_invoked);211 RUN_TEST(test_sqlite3MemSetDefault_settitle_reflected_in_dump);212 return UNITY_END();213}