Files
Baradb/BUGS.md
T
dimgigov 1c42eff7ef
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
fix(vector): use float64 accumulators for distance functions
Vector distance functions (cosine, euclidean, dot, manhattan) returned
float64 but accumulated sums in float32, causing precision loss in SQL
results (e.g. sqrt(2) truncated to float32). Use float64 accumulators
and casts throughout.

docs(bugs): mark BUG-023 and BUG-024 as fixed

The code already cleans up pendingAcks and passes oldAssignments from
rebalance to migrateData; update BUGS.md to match the implementation.
2026-06-12 23:06:19 +03:00

198 lines
12 KiB
Markdown

# Bug Report — BaraDB Codebase Audit
Generated: 2026-05-21
Total: 55 bugs (7 critical, 21 high, 21 medium, 6 low)
**Fixed: 55/55** | **Remaining: 0/55**
---
## Critical — 7/7 fixed
### ~~BUG-001~~ :white_check_mark: `readIdent` infinite loop on multi-byte UTF-8
**File:** `src/barabadb/query/lexer.nim:523-538`**FIXED:** Added `discard l.advanceRune()` to advance `l.pos` in the loop.
### ~~BUG-002~~ :white_check_mark: `Parser.peek` returns uninitialized Token at EOF
**File:** `src/barabadb/query/parser.nim:15-18`**FIXED:** Added missing `return` keyword.
### ~~BUG-003~~ :white_check_mark: `flushUnsafe` writes WAL without `walLock`
**File:** `src/barabadb/storage/lsm.nim:808-810`**FIXED:** Wrapped WAL writes in `acquire(db.walLock)` / `release(db.walLock)`.
### ~~BUG-004~~ :white_check_mark: `checkpoint` calls `flushUnsafe` with no lock
**File:** `src/barabadb/storage/lsm.nim:832-836`**FIXED:** Entire checkpoint now runs under lock; WAL rotate uses `walLock`.
### ~~BUG-005~~ :white_check_mark: Compaction deletes source SSTables without verifying output
**File:** `src/barabadb/storage/compaction.nim:124-128`**FIXED:** Added `verifySSTable` check before deleting sources.
### ~~BUG-006~~ :white_check_mark: `healthCheck` leaks lock on exception
**File:** `src/barabadb/core/replication.nim:227-248`**FIXED:** Snapshot replicas under lock, release, then do network I/O.
### ~~BUG-007~~ :white_check_mark: `hmacSha256` truncates keys > 64 bytes to hex string
**File:** `src/barabadb/protocol/auth.nim:73-79`**FIXED:** Changed `k = $hash` to `k = cast[string](hash)` for raw bytes.
---
## High — 21/21 fixed
### ~~BUG-008~~ :white_check_mark: `loadExistingDatabases` / `ensureDefaultDatabase` without lock
**File:** `src/barabadb/core/registry.nim:55-70, 78-90`**FIXED:** Added lock around `reg.databases` modifications.
### ~~BUG-009~~ :white_check_mark: `compactVersions` modifies shared state without lock
**File:** `src/barabadb/core/mvcc.nim:329-354`**FIXED:** Made private (removed `*`), only called from `commit` which holds lock.
### ~~BUG-010~~ :white_check_mark: Deadlock detector edges never cleaned up
**File:** `src/barabadb/core/mvcc.nim:191-199`**FIXED:** Added `removeWait` before returning on conflict. Also fixed in `delete`.
### ~~BUG-011~~ :white_check_mark: `close` leaks WAL/SSTable on exception
**File:** `src/barabadb/storage/lsm.nim:842-851`**FIXED:** Wrapped in `try/finally` to guarantee cleanup.
### ~~BUG-012~~ :white_check_mark: B-Tree `remove` does not rebalance
**File:** `src/barabadb/storage/btree.nim`**FIXED:** Implemented full B-tree delete rebalancing: `borrowFromLeft`/`borrowFromRight` (borrow key + child from sibling, update parent separator), `mergeWithLeft`/`mergeWithRight` (merge with sibling by pulling down parent separator), `rebalanceAfterDelete` (orchestrates borrow-or-merge, recursive parent rebalancing, root shrinking).
### ~~BUG-013~~ :white_check_mark: Compaction `except: discard` swallows all exceptions
**File:** `src/barabadb/storage/compaction.nim:76-84`**FIXED:** Catches `CatchableError`, logs, and aborts compaction without deleting sources.
### ~~BUG-014~~ :white_check_mark: `headerSize = 36` should be 40 — wrong CRC range
**File:** `src/barabadb/storage/lsm.nim:212,293,334`**FIXED:** Changed all three occurrences from 36 to 40.
### ~~BUG-015~~ :white_check_mark: `**` power operator tokenized but never parsed
**File:** `src/barabadb/query/parser.nim:270-282`**FIXED:** Added `parsePower` function (right-associative) between `parsePostfix` and `parseMulDiv`.
### ~~BUG-016~~ :white_check_mark: `NOT a = b` wrong precedence
**File:** `src/barabadb/query/parser.nim:297-345`**FIXED:** Moved NOT wrap to AFTER the comparison while loop.
### ~~BUG-017~~ :white_check_mark: `COUNT(DISTINCT col)` DISTINCT flag lost
**File:** `src/barabadb/query/parser.nim:141-164`**FIXED:** Added `funcDistinct` field to `nkFuncCall` node in AST, set in parser.
### ~~BUG-018~~ :white_check_mark: Expression UDFs always return null
**File:** `src/barabadb/query/udf.nim:73-80`**FIXED:** Raises descriptive error directing to use query evaluator.
### ~~BUG-019~~ :white_check_mark: `substr` crashes on out-of-bounds index
**File:** `src/barabadb/query/udf.nim:176-188`**FIXED:** Added bounds check, returns empty string for out-of-bounds.
### ~~BUG-020~~ :white_check_mark: Raft accepts stale term vote/append replies
**File:** `src/barabadb/core/raft.nim:352-391`**FIXED:** Added `if reply.term < node.currentTerm: return` in both handlers.
### ~~BUG-021~~ :white_check_mark: Raft `becomeFollower` on `term >= currentTerm`
**File:** `src/barabadb/core/raft.nim:269-271`**FIXED:** Changed `>=` to `>`; `leaderId` assignment still happens unconditionally.
### ~~BUG-022~~ :white_check_mark: `shipToReplica` socket leak
**File:** `src/barabadb/core/replication.nim:94-113`**FIXED:** Used `defer: sock.close()`.
### ~~BUG-023~~ :white_check_mark: `pendingAcks` never cleaned up in sync/semi-sync
**File:** `src/barabadb/core/replication.nim:131-199`**FIXED:** `writeLsn` now removes acked replica IDs from `pendingAcks` and deletes the LSN entry once fully acked; `ackLsn` also cleans up on replica acknowledgement.
### ~~BUG-024~~ :white_check_mark: `rebalance` loses old assignments
**File:** `src/barabadb/core/sharding.nim:221-241`**FIXED:** `rebalance` returns the old shard assignments; callers (`addNode`/`removeNode`) pass them to `migrateData` for correct data migration.
### ~~BUG-025~~ :white_check_mark: `deserializeValue` missing bounds checks
**File:** `src/barabadb/protocol/wire.nim:216-227`**FIXED:** Added bounds checks for `fkBool`, `fkInt8`, `fkInt16`.
### ~~BUG-026~~ :white_check_mark: `verifyToken` parseInt throws on malformed claims
**File:** `src/barabadb/protocol/auth.nim:175-177`**FIXED:** Wrapped in `try/except ValueError`.
### ~~BUG-027~~ :white_check_mark: 2PC leaves participants prepared on network failure
**File:** `src/barabadb/core/disttxn.nim:150-200`**FIXED:** Added `rollbackPending`/`commitPending` flags and recovery warnings.
### ~~BUG-028~~ :white_check_mark: JWT DB switch never decrements old connection count
**File:** `src/barabadb/core/server.nim:504-520`**FIXED:** Decrement old DB count before incrementing new one.
---
## Medium — 21/21 fixed
### ~~BUG-029~~ :white_check_mark: `loadConfigFromJson` silently swallows errors
**File:** `src/barabadb/core/config.nim:121-124`**FIXED:** Logs warnings instead of `discard`.
### ~~BUG-030~~ :white_check_mark: Default JWT secret hardcoded in binary
**File:** `src/barabadb/core/config.nim:182-185`**FIXED:** Returns empty string; callers must handle missing secret.
### ~~BUG-031~~ :white_check_mark: `dropDatabase` closes LSMTree before removing from registry
**File:** `src/barabadb/core/registry.nim:133-161`**FIXED:** Delete from registry first, then close/cleanup outside lock.
### ~~BUG-032~~ :white_check_mark: MERGE missing DELETE / DO NOTHING
**File:** `src/barabadb/query/parser.nim:902-958`**FIXED:** Added `tkDo`/`tkNothing` tokens, `mergeMatchedDelete`/`mergeNotMatchedNothing`/`mergeMatchedCondition` AST fields, and loop-based parser for multiple WHEN branches.
### ~~BUG-033~~ :white_check_mark: `inferExpr` miscategorizes binary operators as unary
**File:** `src/barabadb/query/ir.nim:291-301`**FIXED:** Removed binary operators from unary case, added `irNeg` handling.
### ~~BUG-034~~ :white_check_mark: `codegenExpr` is no-op for most expression types
**File:** `src/barabadb/query/codegen.nim:50-67`**FIXED:** Literal/field/aggregate now return proper storage ops; unary/binary propagate children.
### ~~BUG-035~~ :white_check_mark: `readEntries` leaks FileStream on early return
**File:** `src/barabadb/storage/wal.nim:211-213`**FIXED:** Wrapped in `try/finally` with `s.close()`.
### ~~BUG-036~~ :white_check_mark: mmap reads allow negative offset
**File:** `src/barabadb/storage/mmap.nim:83+`**FIXED:** Added `offset < 0` checks to all read functions.
### ~~BUG-037~~ :white_check_mark: Raft log index conflates entry index with array position
**File:** `src/barabadb/core/raft.nim:287-290`**FIXED:** Added `findLogEntryByIndex` helper that searches by logical index instead of assuming `index - 1 == array_position`.
### ~~BUG-038~~ :white_check_mark: `becomeFollower` doesn't clear `nextIndex`/`matchIndex`
**File:** `src/barabadb/core/raft.nim:209-214`**FIXED:** Added `clear()` for both tables.
### ~~BUG-039~~ :white_check_mark: Gossip assigns wrong port to new nodes
**File:** `src/barabadb/core/gossip.nim:295-302`**FIXED:** Extracts port from `senderAddr` ("host:port") instead of using local `gp.gossipPort`.
### ~~BUG-040~~ :white_check_mark: `getShardRange` overlapping range boundaries
**File:** `src/barabadb/core/sharding.nim:70-74`**FIXED:** Exclusive upper bound for non-last shards.
### ~~BUG-041~~ :white_check_mark: `getShardHash` divides by zero
**File:** `src/barabadb/core/sharding.nim:66-68`**FIXED:** Returns -1 if `shards.len == 0`.
### ~~BUG-042~~ :white_check_mark: `connectWithTimeout` missing SO_ERROR check
**File:** `src/barabadb/core/replication.nim:80-92`**FIXED:** Added `getsockopt(SO_ERROR)` verification.
### ~~BUG-043~~ :white_check_mark: Dead code: duplicate ON UPDATE in ON DELETE
**File:** `src/barabadb/query/parser.nim:1081-1087`**FIXED:** Removed duplicate branches.
### ~~BUG-044~~ :white_check_mark: LIMIT cost ignores offset
**File:** `src/barabadb/query/codegen.nim:242-246`**FIXED:** Cost now factors in `offset + limit` — high offset no longer treated as cheap.
### ~~BUG-045~~ :white_check_mark: `contains` UDF cross-type mismatch
**File:** `src/barabadb/query/udf.nim:212-234`**FIXED:** Added cross-type numeric comparison (int64/int32/float64).
### ~~BUG-046~~ :white_check_mark: MmapFile.close() potential infinite recursion
**File:** `src/barabadb/storage/mmap.nim:133-137`**FIXED:** Qualified `close` as `posix.close`.
### ~~BUG-047~~ :white_check_mark: `sendDistTxnRpc` socket leak
**File:** `src/barabadb/core/disttxn.nim:93-109`**FIXED:** Used `defer: sock.close()`.
### ~~BUG-048~~ :white_check_mark: Saga compensation skips on failure
**File:** `src/barabadb/core/disttxn.nim:282-293`**FIXED:** Wrapped each `compensate()` in `try/except`, logs and continues.
### ~~BUG-049~~ :white_check_mark: SCRAM reveals user existence
**File:** `src/barabadb/protocol/auth.nim:207-208`**FIXED:** Changed error message from "Unknown user: X" to "Authentication failed".
### ~~BUG-050~~ :white_check_mark: `isVisible` doesn't check committedTxnsSet for deleter
**File:** `src/barabadb/core/mvcc.nim:129-141`**FIXED:** Added `committedTxnsSet` check before unconditionally hiding record.
---
## Low — 6/6 fixed
### ~~BUG-051~~ :white_check_mark: `recvExactWithTimeout` abandoned future on timeout
**File:** `src/barabadb/core/server.nim:313-320`**FIXED:** Explicit `return ""` with comment explaining cleanup.
### ~~BUG-052~~ :white_check_mark: `readNumber` produces invalid float for trailing dot
**File:** `src/barabadb/query/lexer.nim:508-521`**FIXED:** Appends "0" for trailing dot (`123.``123.0`).
### ~~BUG-053~~ :white_check_mark: `substr(s, start)` returns rest-of-string
**File:** `src/barabadb/query/udf.nim:187`**FIXED:** Now returns single character `s[start]` for 2-arg form.
### ~~BUG-054~~ :white_check_mark: `readUint32` → `int` truncation on 32-bit
**File:** `src/barabadb/protocol/wire.nim:136,147`**FIXED:** Store raw uint32 before cast, check for negative result after cast.
### ~~BUG-055~~ :white_check_mark: PageCache `put` resets `lastAccess` to 0
**File:** `src/barabadb/storage/compaction.nim:196-213`**FIXED:** Removed unused `lastAccess` field entirely; LRU uses `accessOrder` seq.
---
## Summary
| Status | Count |
|--------|-------|
| Fixed | 55 |
| Remaining | 0 |
All identified bugs have been resolved.