Conversation
|
Tagging subscribers to this area: @dotnet/area-system-formats-tar |
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/26cfdebb-c9b4-43c7-908e-b1d9ce2f1cd6 Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Fixes TarReader_SparseFileTests failing under Native AOT outerloop by removing reflection-based access to internal TAR header state (which is trim-sensitive) and replacing it with [UnsafeAccessor]-based access that is AOT-/trimmer-friendly.
Changes:
- Replace reflection (
GetField/GetProperty/GetValue) inWriteSparseEntrywith[UnsafeAccessor]. - Unwrap
ReadOnlyDictionary<TKey,TValue>to its backingIDictionary<TKey,TValue>via a genericReadOnlyDictionaryAccessors<TKey,TValue>helper to injectGNU.sparse.realsize. - Update usings to remove
System.Reflectionand add required namespaces forReadOnlyDictionary+UnsafeAccessor.
|
Copilot came up with a creative replacement that I scratched my head about for a bit. We can ask it to keep using reflection, just rewrite it into |
|
/azp list |
|
oh, then nativeAoT was already run Seems like the fix works, thanks again |
|
/ba-g test failure is #126867 |
TarReader_SparseFileTests.WriteSparseEntryused reflection to injectGNU.sparse.realsizeintoTarEntry._header.ExtendedAttributesafter construction (to bypass validation for negative-value test cases). Under Native AOT outerloop runs, the trimmer removes metadata for these internal members, causingNullReferenceException.Changes
GetField/GetProperty/GetValue) inWriteSparseEntrywith[UnsafeAccessor], which is AOT-safe and statically analyzable by the trimmer.Dictionary<string, string>by calling the publicPaxTarEntry.ExtendedAttributesproperty (which lazily initializes_header._ea) and then unwrapping theReadOnlyDictionary<string, string>via a generic accessor class targeting the stablem_dictionaryfield.ReadOnlyDictionaryAccessors<TKey, TValue>private nested class (required pattern for[UnsafeAccessor]on a generic target type):using System.Reflection; addedusing System.Collections.ObjectModelandusing System.Runtime.CompilerServices.Original prompt
Problem
PR #125283 introduced
TarReader_SparseFileTeststhat use reflection to access internal members, which breaks under Native AOT outerloop runs because the trimmer removes the reflection metadata.The failing test:
Root Cause
In
src/libraries/System.Formats.Tar/tests/TarReader/TarReader.SparseFile.Tests.cs, theWriteSparseEntrymethod uses reflection at lines 40-43:Under Native AOT,
GetFieldandGetPropertyreturn null because reflection metadata for these internal members is not preserved. The!operator then causes a NullReferenceException.Required Fix
Replace the reflection-based access with
[UnsafeAccessor]attribute, which works under Native AOT. The internal types/members that need to be accessed:TarEntry._header- aninternalfield of typeTarHeaderon the abstract classTarEntry(insrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs, line 17:internal TarHeader _header;)TarHeader.ExtendedAttributes- aninternalproperty on thesealedclassTarHeaderthat returnsDictionary<string, string>. It's defined as:The backing field is
private Dictionary<string, string>? _ea;The
TarHeaderclass isinternal sealed partial class TarHeaderin namespaceSystem.Formats.Tar.Implementation
In the test file
src/libraries/System.Formats.Tar/tests/TarReader/TarReader.SparseFile.Tests.cs:Add
using System.Runtime.CompilerServices;at the top.Remove
using System.Reflection;(should no longer be needed).Add
[UnsafeAccessor]static extern methods to the test class (or as file-scoped static methods). For example:Note:
TarHeaderis internal, so the test project needs to have access to it. Check if the test project already hasInternalsVisibleToor uses[assembly: InternalsVisibleTo]. If not, you might need to access the_eafield directly instead of going through theExtendedAttributesproperty:However, since
UnsafeAccessorwithUnsafeAccessorKind.Fieldreturns arefto the field, and_eamight be null, you'd need to handle the initialization. An alternative approach: since theExtendedAttributesproperty initializes_eavia??=, you could use the_eafield ref but it might be simpler to just set it.Actually, the simplest approach: The test only needs to add a key to the internal extended attributes dictionary. Since
TarHeaderisinternal, check if the test assembly can see it. Look forInternalsVisibleToin the product assembly. If the tests can already seeTarHeader, then[UnsafeAccessor]only needs to access_headeronTarEntry(since_headerisinternalbut the classTarHeaderitself is also internal).Important:
[UnsafeAccessor]can access internal types from other assemblies. The field accessor returns a ref, so you can directly work with it. The method should look something like:But since
TarHeaderis internal to the product assembly and can't be named in the test assembly's source code directly... you need to check if test projects haveInternalsVisibleTo.WriteSparseEntrywith calls to the[UnsafeAccessor]methods to get the_headerfield and then theExtendedAttributes/_eafield, and setea["GNU.sparse.realsize"] = realSize.ToString();.Please check whether the test project has access to internal types (via InternalsVisibleTo or similar) and choose the simplest working approach. The key requirement is that the code must work under Native AOT without relying on reflection APIs (`Type....
This pull request was created from Copilot chat.