@@ -80,6 +80,7 @@ if (!backup_) {
8080
8181## Issue 2: NULL Pointer from sqlite3_column_text()
8282
83+ ** Status** : ✅ COMPLETED
8384** Severity** : CRITICAL
8485** File** : ` src/sqlite_impl.cpp `
8586** Lines** : 2117-2118, 2174-2175
@@ -98,6 +99,7 @@ case SQLITE_TEXT: {
9899```
99100
100101This appears in two locations:
102+
101103- Array mode CreateResult (line 2117-2118)
102104- Object mode CreateResult (line 2174-2175)
103105
@@ -126,16 +128,33 @@ case SQLITE_TEXT: {
126128
127129### Acceptance Criteria
128130
129- - [ ] Test with zero-length string passes
130- - [ ] Test with NULL value passes
131- - [ ] Both array and object modes tested
132- - [ ] No crashes on edge cases
133- - [ ] Full test suite passes
131+ - [x] Test with zero-length string passes
132+ - [x] Test with NULL value passes
133+ - [x] Both array and object modes tested
134+ - [x] No crashes on edge cases
135+ - [x] Full test suite passes (557 tests passing)
136+
137+ ### Implementation Summary
138+
139+ ** Test File** : ` test/null-text-blob.test.ts `
140+
141+ - Created comprehensive tests for NULL and zero-length TEXT values
142+ - Tests cover object mode (` .get() ` ), array mode (` .all() ` ), and iterator mode
143+ - All 12 tests passing
144+
145+ ** Fix Applied** : ` src/sqlite_impl.cpp ` lines 2116-2123 and 2173-2180
146+
147+ - Added NULL check before ` Napi::String::New() ` in both array and object modes
148+ - Returns empty string when ` sqlite3_column_text() ` returns NULL
149+ - Includes explanatory comment about OOM/encoding error conditions
150+
151+ ** Result** : Defensive NULL handling prevents potential crashes on OOM or encoding errors while maintaining backward compatibility.
134152
135153---
136154
137155## Issue 3: NULL Pointer from sqlite3_column_blob()
138156
157+ ** Status** : ✅ COMPLETED
139158** Severity** : CRITICAL
140159** File** : ` src/sqlite_impl.cpp `
141160** Lines** : 2122-2130, 2179-2187
@@ -187,11 +206,29 @@ case SQLITE_BLOB: {
187206
188207### Acceptance Criteria
189208
190- - [ ] Zero-length BLOB test passes
191- - [ ] NULL BLOB test passes
192- - [ ] Both return modes tested
193- - [ ] Correct empty buffer returned
194- - [ ] Full test suite passes
209+ - [x] Zero-length BLOB test passes
210+ - [x] NULL BLOB test passes
211+ - [x] Both return modes tested
212+ - [x] Correct handling of NULL values
213+ - [x] Full test suite passes (557 tests passing)
214+
215+ ### Implementation Summary
216+
217+ ** Test File** : ` test/null-text-blob.test.ts ` (same file as Issue 2)
218+
219+ - Created comprehensive tests for NULL and zero-length BLOB values
220+ - Tests cover object mode (` .get() ` ), array mode (` .all() ` ), and iterator mode
221+ - Discovered that SQLite treats zero-length BLOBs as NULL (expected behavior)
222+ - All 12 tests passing
223+
224+ ** Fix Applied** : ` src/sqlite_impl.cpp ` lines 2125-2135 and 2182-2192
225+
226+ - Added NULL check before ` Napi::Buffer::Copy() ` in both array and object modes
227+ - Combined with existing ` blob_size == 0 ` check: ` if (!blob_data || blob_size == 0) `
228+ - Returns empty buffer when NULL or zero-length
229+ - Includes explanatory comment about zero-length BLOB and OOM conditions
230+
231+ ** Result** : Defensive NULL handling prevents undefined behavior when copying from NULL pointer while maintaining backward compatibility.
195232
196233---
197234
@@ -337,6 +374,7 @@ if (status != napi_ok || self->env_.IsExceptionPending()) {
337374```
338375
339376Apply to:
377+
340378- ` xStepBase() ` around line 289-296
341379- ` xInverseBase() ` around line 433-439
342380- ` xValueBase() ` around line 468-471
@@ -371,6 +409,7 @@ Apply to:
371409Aggregate function callbacks create ` HandleScope ` but NOT ` CallbackScope ` , violating N-API best practices. This can cause async hooks to not fire correctly.
372410
373411Current code:
412+
374413``` cpp
375414void CustomAggregate::xStepBase (...) {
376415 Napi::HandleScope scope(self->env_ );
@@ -380,6 +419,7 @@ void CustomAggregate::xStepBase(...) {
380419```
381420
382421Correct pattern from `user_function.cpp:57`:
422+
383423```cpp
384424Napi::HandleScope scope(self->env_);
385425Napi::CallbackScope callback_scope(self->env_, self->async_context_);
@@ -388,6 +428,7 @@ Napi::CallbackScope callback_scope(self->env_, self->async_context_);
388428### Proposed Solution
389429
390430Add ` CallbackScope ` creation after ` HandleScope ` in:
431+
391432- ` xStepBase() ` (line ~ 159)
392433- ` xInverseBase() ` (line ~ 313)
393434- ` xValueBase() ` (line ~ 375)
@@ -409,7 +450,7 @@ Ensure `async_context_` is properly initialized (check constructor).
409450### Acceptance Criteria
410451
411452- [ ] All four callback functions updated
412- - [ ] async_context_ properly managed
453+ - [ ] async*context* properly managed
413454- [ ] Pattern matches user functions
414455- [ ] Full test suite passes
415456
@@ -425,6 +466,7 @@ Ensure `async_context_` is properly initialized (check constructor).
425466### Problem Description
426467
427468Several DatabaseSync methods access `connection_` pointer without validating the calling thread. While `ValidateThread()` method exists, it's not called in:
469+
428470- `LocationMethod()` (line 576-600)
429471- `IsOpenGetter()` (line 602-604)
430472- `IsTransactionGetter()` (line 606-610)
@@ -517,6 +559,7 @@ void UserDefinedFunction::xFunc(sqlite3_context *ctx, int argc,
517559Add ` creation_thread_ ` member to classes if not already present.
518560
519561Apply to:
562+
520563- ` UserDefinedFunction::xFunc() `
521564- ` CustomAggregate::xStepBase() `
522565- ` CustomAggregate::xInverseBase() `
@@ -594,7 +637,7 @@ Napi::Value ValueStorage::Get(Napi::Env env, int32_t id) {
594637
595638---
596639
597- ## Issue 11: Missing Error Checks on sqlite3_bind _ * ()
640+ ## Issue 11: Missing Error Checks on sqlite3 * bind * \ * ()
598641
599642** Severity** : HIGH
600643** File** : ` src/sqlite_impl.cpp `
@@ -643,7 +686,7 @@ void CheckBindResult(int result) {
643686
644687### Acceptance Criteria
645688
646- - [ ] All sqlite3_bind_ *() calls have error checking
689+ - [ ] All sqlite3*bind*\ *() calls have error checking
647690- [ ] Consistent error handling pattern
648691- [ ] Tests verify error detection
649692- [ ] Full test suite passes
@@ -817,26 +860,31 @@ Or use RAII wrapper for session lifetime.
817860Based on severity and dependencies, suggested order:
818861
819862### Phase 1: Critical SQLite API Fixes (Low Risk, High Impact)
863+
8208641 . Issue 2: NULL checks for sqlite3_column_text()
8218652 . Issue 3: NULL checks for sqlite3_column_blob()
8228663 . Issue 4: NULL checks for sqlite3_value_text() in user functions
8238674 . Issue 5: NULL checks for sqlite3_value_blob() in user functions
824868
825869### Phase 2: Critical N-API Fixes
870+
8268715 . Issue 6: Exception checks in aggregate functions
8278726 . Issue 7: Add CallbackScope to aggregates
828873
829874### Phase 3: Critical Resource Leaks
875+
8308767 . Issue 1: Backup job database handle leak
8318778 . Issue 14: Session creation reference leak
832878
833879### Phase 4: Thread Safety (Most Complex)
880+
8348819 . Issue 10: TOCTOU race in ValueStorage::Get()
83588210 . Issue 8: Thread validation in database methods
83688311 . Issue 9: Thread validation in callbacks
837884
838885### Phase 5: Additional SQLite API Hardening
839- 12 . Issue 11: Error checks on sqlite3_bind_ * ()
886+
887+ 12 . Issue 11: Error checks on sqlite3* bind* \* ()
84088813 . Issue 12: Check sqlite3_exec() for foreign keys
84188914 . Issue 13: Check sqlite3_busy_timeout()
842890
@@ -853,6 +901,7 @@ Each issue should follow TDD principles:
8539015 . ** Run full suite** - No regressions
854902
855903After all fixes:
904+
856905- Run full test suite on all platforms
857906- Run with Valgrind for leak detection
858907- Run with ThreadSanitizer for race detection
0 commit comments