AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdint.h>6 7/* Target under test */8void sqlite3RCStrUnref(void *z);9 10/* Helper: allocate an RCStr header plus payload and return both the header and the z pointer */11static RCStr* helper_alloc_rcstr(int refCount, size_t payloadSize, void **pzOut){12 size_t nByte = sizeof(RCStr) + payloadSize;13 RCStr *p = (RCStr*)sqlite3_malloc(nByte ? nByte : 1);14 TEST_ASSERT_NOT_NULL_MESSAGE(p, "sqlite3_malloc for RCStr failed");15 /* Zero the header only; payload can be anything */16 memset(p, 0, sizeof(RCStr));17 p->nRCRef = refCount;18 char *z = (char*)&p[1];19 if( payloadSize>0 ){20 memset(z, 0xAB, payloadSize);21 z[payloadSize-1] = 0; /* ensure a trailing 0 if size>0 for safety */22 }23 *pzOut = (void*)z;24 return p;25}26 27void setUp(void) {28 /* no-op */29}30void tearDown(void) {31 /* no-op */32}33 34/* Test: When nRCRef==2, it decrements to 1 and does not free */35void test_sqlite3RCStrUnref_decrement_from_two(void){36 void *z = NULL;37 RCStr *p = helper_alloc_rcstr(2, 16, &z);38 39 /* Sanity: pointer arithmetic expectation */40 RCStr *calc = (RCStr*)z;41 calc--;42 TEST_ASSERT_EQUAL_PTR(p, calc);43 44 sqlite3RCStrUnref(z);45 TEST_ASSERT_EQUAL_INT(1, p->nRCRef);46 47 /* Final unref should free. Do not access p after this call. */48 sqlite3RCStrUnref(z);49}50 51/* Test: When nRCRef>2 (e.g., 5), it decrements by exactly 1 and remains valid */52void test_sqlite3RCStrUnref_decrement_from_five(void){53 void *z = NULL;54 RCStr *p = helper_alloc_rcstr(5, 8, &z);55 56 sqlite3RCStrUnref(z);57 TEST_ASSERT_EQUAL_INT(4, p->nRCRef);58 59 sqlite3RCStrUnref(z);60 TEST_ASSERT_EQUAL_INT(3, p->nRCRef);61 62 /* Clean up remaining references: two more to reach 1, then final free */63 sqlite3RCStrUnref(z); /* 3->2 */64 TEST_ASSERT_EQUAL_INT(2, p->nRCRef);65 sqlite3RCStrUnref(z); /* 2->1 */66 TEST_ASSERT_EQUAL_INT(1, p->nRCRef);67 68 /* Final unref frees memory. Do not touch p after this. */69 sqlite3RCStrUnref(z);70}71 72/* Test: When nRCRef==1, it frees the allocation (no crash) */73void test_sqlite3RCStrUnref_free_on_one(void){74 void *z = NULL;75 RCStr *p = helper_alloc_rcstr(1, 4, &z);76 (void)p; /* not used further to avoid use-after-free */77 78 /* This should free the RCStr; success is absence of crash. */79 sqlite3RCStrUnref(z);80 81 /* Do not dereference p here; it has been freed. */82}83 84/* Test: Multiple independent RCStr objects do not interfere with each other */85void test_sqlite3RCStrUnref_multiple_independent(void){86 void *z1 = NULL;87 void *z2 = NULL;88 RCStr *p1 = helper_alloc_rcstr(3, 12, &z1);89 RCStr *p2 = helper_alloc_rcstr(2, 12, &z2);90 91 /* Unref first object once */92 sqlite3RCStrUnref(z1);93 TEST_ASSERT_EQUAL_INT(2, p1->nRCRef);94 TEST_ASSERT_EQUAL_INT(2, p2->nRCRef); /* unaffected */95 96 /* Unref second object once */97 sqlite3RCStrUnref(z2);98 TEST_ASSERT_EQUAL_INT(2, p1->nRCRef);99 TEST_ASSERT_EQUAL_INT(1, p2->nRCRef);100 101 /* Finalize second object (free) */102 sqlite3RCStrUnref(z2);103 /* Do not access p2 beyond this point */104 105 /* Clean up first object: decrement to 1 then final free */106 sqlite3RCStrUnref(z1); /* 2->1 */107 TEST_ASSERT_EQUAL_INT(1, p1->nRCRef);108 sqlite3RCStrUnref(z1); /* 1->free */109}110 111/* A simple stress: create and release several RCStr objects (nRCRef==2) */112void test_sqlite3RCStrUnref_stress_small_batch(void){113 enum { N = 10 };114 RCStr *headers[N];115 void *ptrs[N];116 memset(headers, 0, sizeof(headers));117 memset(ptrs, 0, sizeof(ptrs));118 for(int i=0;i<N;i++){119 headers[i] = helper_alloc_rcstr(2, 16, &ptrs[i]);120 }121 for(int i=0;i<N;i++){122 sqlite3RCStrUnref(ptrs[i]); /* 2->1 */123 TEST_ASSERT_EQUAL_INT(1, headers[i]->nRCRef);124 }125 for(int i=0;i<N;i++){126 sqlite3RCStrUnref(ptrs[i]); /* 1->free */127 }128}129 130int main(void){131 UNITY_BEGIN();132 RUN_TEST(test_sqlite3RCStrUnref_decrement_from_two);133 RUN_TEST(test_sqlite3RCStrUnref_decrement_from_five);134 RUN_TEST(test_sqlite3RCStrUnref_free_on_one);135 RUN_TEST(test_sqlite3RCStrUnref_multiple_independent);136 RUN_TEST(test_sqlite3RCStrUnref_stress_small_batch);137 return UNITY_END();138}