Be more specific? OK
---
CopyNode broken
`CopyNode` duplicates only the parent; every child pointer is still shared
nodeCopy.setChildren(make([]*node, len(n.children)))
copy(nodeCopy.children, n.children) // pointers reused
https://github.com/sirgallo/cmapv2/blob/main/node.go#L11-L17Any later mutation (for example `setValue`) writes through those shared pointers, so readers and historical snapshots are modified concurrently -- invalid, data race, memory model violation
---
Bitmap corruption
`SetBit` uses XOR rather than “set”:
func SetBit(bitmap uint32, position int) uint32 { return bitmap ^ (1 << position) }
https://github.com/sirgallo/cmapv2/blob/main/utils.go#L41-L4...Calling it twice on the same index flips the bit back to 0. During branch-creation on insert and during delete, this function is invoked multiple times on the same index, clearing a bit that should remain set and leaving orphaned children.
---
Invalid assumptions re: interior pointers
Only the root pointer is read with `atomic.LoadPointer`. All deeper fields like `children[pos]`, `bitmap`, and the byte-slice keys/values, are accessed directly after a successful CAS. Readers therefore race with writers that mutate these fields in place -- race condition, memory model violation, etc.
pos := cMap.getPosition(node.Bitmap(), hash, level)
if node.Child(pos).IsLeaf() && bytes.Equal(key, node.Child(pos).Key()) {
return node.Child(pos).Value()
}
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L5...---
All xxxRecursive functions rely on those invalid interior pointer assumptions
Sequence in `putRecursive` / `deleteRecursive` is
1. `curr := atomic.LoadPointer(ptr)`
2. Build `nodeCopy`
3. Recurse; grandchildren are mutated in place
4. `atomic.CompareAndSwap(ptr, curr, nodeCopy)`
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1...If another goroutine has already swapped in a different copy of `curr` (and mutated it) the CAS still succeeds because the pointer value is unchanged, merging incompatible sub-tries and corrupting the data
---
Use-after-free in sync.Pool
On CAS failure the freshly built `nodeCopy` is immediately returned to a `sync.Pool` -- undefined behavior
cMap.pool.PutNode(nodeCopy) // may race with outstanding readers
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1...Other goroutines still holding references to that node can now access a reclaimed object, oops.
---
K/V Aliasing
Keys and values (both []byte slices, which are not safe for concurrent r/w access) are stored by reference, a mistake:
n.setKey(key)
n.setValue(value)
If the caller mutates those slices later (or concurrently in another goroutine), data races ahoy
---
Reader panics, etc.
- `getRecursive` accesses `children[pos]` without bounds or nil checks, concurrent shrink can make `pos` invalid
- `GetIndex` allows a negative `shiftSize` once `level >= 7` with `chunkSize = 5`, producing nonsense indices and potential slice-out-of-bounds
---
CopyNode broken
`CopyNode` duplicates only the parent; every child pointer is still shared
https://github.com/sirgallo/cmapv2/blob/main/node.go#L11-L17Any later mutation (for example `setValue`) writes through those shared pointers, so readers and historical snapshots are modified concurrently -- invalid, data race, memory model violation
---
Bitmap corruption
`SetBit` uses XOR rather than “set”:
https://github.com/sirgallo/cmapv2/blob/main/utils.go#L41-L4...Calling it twice on the same index flips the bit back to 0. During branch-creation on insert and during delete, this function is invoked multiple times on the same index, clearing a bit that should remain set and leaving orphaned children.
---
Invalid assumptions re: interior pointers
Only the root pointer is read with `atomic.LoadPointer`. All deeper fields like `children[pos]`, `bitmap`, and the byte-slice keys/values, are accessed directly after a successful CAS. Readers therefore race with writers that mutate these fields in place -- race condition, memory model violation, etc.
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L5...---
All xxxRecursive functions rely on those invalid interior pointer assumptions
Sequence in `putRecursive` / `deleteRecursive` is
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1...If another goroutine has already swapped in a different copy of `curr` (and mutated it) the CAS still succeeds because the pointer value is unchanged, merging incompatible sub-tries and corrupting the data
---
Use-after-free in sync.Pool
On CAS failure the freshly built `nodeCopy` is immediately returned to a `sync.Pool` -- undefined behavior
https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1...Other goroutines still holding references to that node can now access a reclaimed object, oops.
---
K/V Aliasing
Keys and values (both []byte slices, which are not safe for concurrent r/w access) are stored by reference, a mistake:
If the caller mutates those slices later (or concurrently in another goroutine), data races ahoy---
Reader panics, etc.