fix(array): retain dictionary before replacement#926
Conversation
zeroshade
left a comment
There was a problem hiding this comment.
Correct fix for a real use-after-free — releasing the old dictionary before retaining the replacement could free-then-resurrect a cleared *Data when the parent held the last reference. The retain-before-release ordering now matches how Reset handles buffers/children, and the regression test captures the exact case. One test nit inline.
| d.dictionary = dict.(*Data) | ||
|
|
||
| if newDict != nil { | ||
| newDict.Retain() |
There was a problem hiding this comment.
Retain-before-release ordering is correct. Please add a SetDictionary(nil) test (clearing is now supported per the PR description but untested), and optionally one asserting the explicit panic for a non-*array.Data implementation.
zeroshade
left a comment
There was a problem hiding this comment.
LGTM. Retaining the replacement dictionary before releasing the old one is the correct fix, and the same-pointer replacement / nil-clear tests cover it well. Thanks!
Data.SetDictionary released the existing dictionary before retaining the replacement. Replacing a dictionary with the same pointer while the parent held the final reference could therefore clear the dictionary before resurrecting its reference.
This retains the validated replacement first, swaps it into the Data object, then releases the previous dictionary. It also handles nil input and reports an explicit panic for an invalid dictionary data implementation.
Tests: