Validate null before mutating CodeNamespaceImportCollection - #132369
Validate null before mutating CodeNamespaceImportCollection#132369nileshpatil6 wants to merge 1 commit into
Conversation
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
@dotnet-policy-service agree |
There was a problem hiding this comment.
Pull request overview
This PR fixes CodeNamespaceImportCollection becoming unusable after null is added via non-generic IList APIs or via the typed indexer setter. It does so by ensuring Namespace is read (and thus the same NullReferenceException is thrown) before mutating the backing _data collection, matching the existing behavior of Add(CodeNamespaceImport) and preventing the collection from entering an invalid state.
Changes:
- Add a small helper (
Validated) that forcesvalue.Namespaceto be evaluated before storing into_data. - Route
IList.Add,IList.Insert, andCodeNamespaceImportCollection.this[int].setthrough that helper sonullthrows before mutation. - Add regression tests covering the
IList.Add,IList.Insert, and indexer-setter null scenarios, including verifying the collection remains usable afterwards.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/libraries/System.CodeDom/src/System/CodeDom/CodeNamespaceImportCollection.cs | Validates Namespace prior to mutation for IList mutation paths and the typed indexer setter to prevent invalid internal state. |
| src/libraries/System.CodeDom/tests/System/CodeDom/CodeNamespaceImportCollectionTests.cs | Adds regression tests ensuring null mutation paths throw and do not corrupt the collection for subsequent operations. |
|
Tagging subscribers to this area: @dotnet/area-system-codedom |
huoyaoyuan
left a comment
There was a problem hiding this comment.
Thanks you for your interest of contribution. System.CodeDom isn't being actively developed. Before continuing, we should let the area owner to decide this is an issue we actually care, and whether to preserve NullReferenceException or use ArgumentNullException instead.
| // point, before the store. | ||
| private static CodeNamespaceImport Validated(CodeNamespaceImport value) | ||
| { | ||
| _ = value.Namespace; |
There was a problem hiding this comment.
This is not the correct way to throw NullReferenceException. The compilers are allowed to treat the _ access as unused, despite they aren't currently doing so.
Also, it's not the pattern we use to validate a parameter then return it in a helper method.
Fixes #131870.
Add(CodeNamespaceImport)readsvalue.Namespacebefore it touches_data, so a null argument throwsNullReferenceExceptionand the collection is left untouched. That is the behaviourAdd_Null_ThrowsNullReferenceExceptionpins.Three other paths store first and validate afterwards, if at all:
IList.Addis_data.Add((CodeNamespaceImport)value). The cast succeeds for null,ArrayList.Addaccepts it, and the method never callsSyncKeys(), so it does not throw at all. The null stays in_data, and the next operation that callsSyncKeys()throws while enumerating it.IList.Insertinserts and then callsSyncKeys(), which throws onc.Namespaceafter the element is already in the list._data[index] = value.So the collection ends up in a state where every later mutation throws, which is what the issue reports.
This routes the three paths through a small helper that reads
Namespacebefore the store, so they throw the sameNullReferenceExceptionat the same point asAdd(CodeNamespaceImport)and leave the collection unchanged.I checked the behaviour against the shipped
System.CodeDom8.0.0 first, then against the patched class compiled standalone:Added three tests next to
Add_Null_ThrowsNullReferenceException, each asserting both halves: that the null throws, and that a normal insert still works afterwards. The second half is the part that fails on current main.I kept
NullReferenceExceptionrather than switching toArgumentNullException, since the existing tests assert it forAddandAddRangeand changing it would be a separate, observable break. Happy to switch if you would rather these paths threwArgumentNullException.One thing I noticed but did not change:
IList.Addalso never updates_keys, so a non-null value added through it is invisible to the duplicate check inAdd(CodeNamespaceImport)and can be added twice. RoutingIList.Addthrough the publicAddwould fix that too, but it changes the returned index and applies the dedup, so it seemed better left out of a null-handling fix. Let me know if you want it here.