Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3LeaveMutexAndCloseZombie.c145 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Global counters for destructor invocations */7static int gFuncDestroyedCount = 0;8static int gCollationDestroyedCount = 0;9 10/* Simple scalar function to register */11static void testScalarFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){12  (void)argc;13  (void)argv;14  sqlite3_result_null(ctx);15}16 17/* Destructor for function user data: increments the counter pointed to by p */18static void xUserDataDestroy(void *p){19  if( p ) (*(int*)p)++;20}21 22/* Simple collation compare function */23static int tcolCompare(void *pArg, int aLen, const void *a, int bLen, const void *b){24  (void)pArg;25  int n = aLen < bLen ? aLen : bLen;26  int c = memcmp(a, b, n);27  if( c==0 ){28    if( aLen < bLen ) return -1;29    if( aLen > bLen ) return 1;30    return 0;31  }32  return c;33}34 35/* Destructor for collation user data: increments the counter pointed to by p */36static void xCollationDestroy(void *p){37  if( p ) (*(int*)p)++;38}39 40/* Helper: open an in-memory database and assert success */41static sqlite3* open_memory_db(void){42  sqlite3 *db = 0;43  int rc = sqlite3_open(":memory:", &db);44  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);45  TEST_ASSERT_NOT_NULL(db);46  return db;47}48 49void setUp(void) {50  gFuncDestroyedCount = 0;51  gCollationDestroyedCount = 0;52}53void tearDown(void) {54  /* nothing */55}56 57/* 1) Non-zombie: should just release the mutex and return; DB remains usable */58void test_sqlite3LeaveMutexAndCloseZombie_nonZombie_earlyReturn_doesNotClose(void){59  sqlite3 *db = open_memory_db();60 61  /* Ensure not zombie (normal open state). */62  TEST_ASSERT_NOT_EQUAL_INT(SQLITE_STATE_ZOMBIE, db->eOpenState);63 64  /* Call under mutex; function should only unlock and return. */65  sqlite3_mutex_enter(db->mutex);66  sqlite3LeaveMutexAndCloseZombie(db);67 68  /* DB should remain usable. Prepare/step/finalize a simple statement. */69  sqlite3_stmt *pStmt = 0;70  int rc = sqlite3_prepare_v2(db, "SELECT 1", -1, &pStmt, 0);71  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);72  TEST_ASSERT_NOT_NULL(pStmt);73  rc = sqlite3_step(pStmt);74  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);75  rc = sqlite3_finalize(pStmt);76  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);77 78  /* Close normally. */79  rc = sqlite3_close(db);80  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);81}82 83/* 2) Zombie but busy (unfinalized stmt): should only release mutex and return; DB not closed */84void test_sqlite3LeaveMutexAndCloseZombie_zombieBusy_stmt_earlyReturn(void){85  sqlite3 *db = open_memory_db();86 87  /* Create an unfinalized statement so connectionIsBusy(db) == true */88  sqlite3_stmt *pStmt = 0;89  int rc = sqlite3_prepare_v2(db, "SELECT 42", -1, &pStmt, 0);90  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);91  TEST_ASSERT_NOT_NULL(pStmt);92 93  /* Mark connection as zombie and call target under mutex */94  db->eOpenState = SQLITE_STATE_ZOMBIE;95  sqlite3_mutex_enter(db->mutex);96  sqlite3LeaveMutexAndCloseZombie(db);97 98  /* Verify DB not closed by finalizing the statement successfully */99  rc = sqlite3_finalize(pStmt);100  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101 102  /* Now the connection is zombie and not busy; close it fully via target */103  sqlite3_mutex_enter(db->mutex);104  sqlite3LeaveMutexAndCloseZombie(db);105 106  /* db has been freed; do not access it further. Success is no crash. */107}108 109/* 3) Zombie and idle: should free connection and invoke user destructors */110void test_sqlite3LeaveMutexAndCloseZombie_zombieIdle_calls_destructors_and_frees(void){111  sqlite3 *db = open_memory_db();112 113  /* Register a user function with a destructor */114  int rc = sqlite3_create_function_v2(115      db, "tfunc", 1, SQLITE_UTF8, &gFuncDestroyedCount,116      testScalarFunc, 0, 0, xUserDataDestroy117  );118  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);119 120  /* Register a collation with a destructor */121  rc = sqlite3_create_collation_v2(122      db, "tcol", SQLITE_UTF8, &gCollationDestroyedCount,123      tcolCompare, xCollationDestroy124  );125  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);126 127  /* Ensure there are no outstanding statements/backups and mark as zombie */128  db->eOpenState = SQLITE_STATE_ZOMBIE;129 130  /* Call target under mutex to force full close */131  sqlite3_mutex_enter(db->mutex);132  sqlite3LeaveMutexAndCloseZombie(db);133 134  /* DB has been freed. Verify destructors were invoked exactly once each. */135  TEST_ASSERT_EQUAL_INT(1, gFuncDestroyedCount);136  TEST_ASSERT_EQUAL_INT(1, gCollationDestroyedCount);137}138 139int main(void){140  UNITY_BEGIN();141  RUN_TEST(test_sqlite3LeaveMutexAndCloseZombie_nonZombie_earlyReturn_doesNotClose);142  RUN_TEST(test_sqlite3LeaveMutexAndCloseZombie_zombieBusy_stmt_earlyReturn);143  RUN_TEST(test_sqlite3LeaveMutexAndCloseZombie_zombieIdle_calls_destructors_and_frees);144  return UNITY_END();145}