Skip to content

Commit 7e1fdd9

Browse files
fix(dataset): prevent nil map panic and remove redundant Clone calls (#125)
Root cause: bart's ModifyPersist calls our Clone() method when cloning nodes. If Clone() returned nil (when called on nil map), that nil was stored in the cloned table. Subsequent callbacks received exists=true with nil data, causing panic in AddID(). Fixes: 1. Clone() now returns initialized map instead of nil 2. Removed redundant manual Clone() calls in updateBatch/RemoveBatch since bart already clones via our Cloner interface before callback 3. Changed RemediationIdsMap{} to make(RemediationIdsMap) for clarity This improves both correctness and performance (no double cloning).
1 parent 4e2cef1 commit 7e1fdd9

File tree

2 files changed

+11
-13
lines changed

2 files changed

+11
-13
lines changed

pkg/dataset/bart_types.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,15 @@ func (s *BartUnifiedIPSet) updateBatch(cur *bart.Table[RemediationIdsMap], opera
146146
if valueLog != nil {
147147
valueLog.Trace("exact prefix exists, merging IDs")
148148
}
149-
// Clone existing data and add the new ID
150-
newData := existingData.Clone()
151-
newData.AddID(valueLog, op.R, op.ID, op.Origin)
152-
return newData, false // false = don't delete
149+
// bart already cloned via our Cloner interface, modify directly
150+
existingData.AddID(valueLog, op.R, op.ID, op.Origin)
151+
return existingData, false // false = don't delete
153152
}
154153
if valueLog != nil {
155154
valueLog.Trace("creating new entry")
156155
}
157156
// Create new data
158-
newData := RemediationIdsMap{}
157+
newData := make(RemediationIdsMap)
159158
newData.AddID(valueLog, op.R, op.ID, op.Origin)
160159
return newData, false // false = don't delete
161160
})
@@ -209,31 +208,30 @@ func (s *BartUnifiedIPSet) RemoveBatch(operations []BartRemoveOp) []*BartRemoveO
209208
return existingData, false // false = don't delete (prefix doesn't exist anyway)
210209
}
211210

212-
// Clone existing data and remove the ID
213-
clonedData := existingData.Clone()
214-
err := clonedData.RemoveID(valueLog, op.R, op.ID)
211+
// bart already cloned via our Cloner interface, modify directly
212+
err := existingData.RemoveID(valueLog, op.R, op.ID)
215213
if err != nil {
216214
if valueLog != nil {
217215
valueLog.Trace("ID not found")
218216
}
219217
results[i] = nil
220-
return existingData, false // false = don't delete, keep original data
218+
return existingData, false // false = don't delete, keep data unchanged
221219
}
222220

223221
// ID was successfully removed - return pointer to the operation for metadata access
224222
// Use index to get pointer to original operation (safe since we don't modify the slice)
225223
results[i] = &operations[i]
226224

227-
if clonedData.IsEmpty() {
225+
if existingData.IsEmpty() {
228226
if valueLog != nil {
229227
valueLog.Trace("removed prefix entirely")
230228
}
231-
return clonedData, true // true = delete the prefix (it's now empty)
229+
return existingData, true // true = delete the prefix (it's now empty)
232230
}
233231
if valueLog != nil {
234232
valueLog.Trace("removed ID from existing prefix")
235233
}
236-
return clonedData, false // false = don't delete, keep modified data
234+
return existingData, false // false = don't delete, keep modified data
237235
})
238236
}
239237

pkg/dataset/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func (rM RemediationIdsMap) IsEmpty() bool {
101101
// which use structural typing to detect the Clone method.
102102
func (rM RemediationIdsMap) Clone() RemediationIdsMap {
103103
if rM == nil {
104-
return nil
104+
return make(RemediationIdsMap)
105105
}
106106
cloned := make(RemediationIdsMap, len(rM))
107107
for k, v := range rM {

0 commit comments

Comments
 (0)