File size: 3,981 Bytes
7510827
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdlib.h>

/* 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();
}