@@ -305,7 +305,7 @@ public virtual AssemblyNameReference ImportReference (SR.AssemblyName name)
305
305
Mixin . CheckName ( name ) ;
306
306
307
307
AssemblyNameReference reference ;
308
- if ( TryGetAssemblyNameReference ( name , out reference ) )
308
+ if ( Mixin . TryGetAssemblyNameReference ( module , name , out reference ) )
309
309
return reference ;
310
310
311
311
reference = new AssemblyNameReference ( name . Name , name . Version )
@@ -320,23 +320,6 @@ public virtual AssemblyNameReference ImportReference (SR.AssemblyName name)
320
320
return reference ;
321
321
}
322
322
323
- bool TryGetAssemblyNameReference ( SR . AssemblyName name , out AssemblyNameReference assembly_reference )
324
- {
325
- var references = module . AssemblyReferences ;
326
-
327
- for ( int i = 0 ; i < references . Count ; i ++ ) {
328
- var reference = references [ i ] ;
329
- if ( name . FullName != reference . FullName ) // TODO compare field by field
330
- continue ;
331
-
332
- assembly_reference = reference ;
333
- return true ;
334
- }
335
-
336
- assembly_reference = null ;
337
- return false ;
338
- }
339
-
340
323
FieldReference ImportField ( SR . FieldInfo field , ImportGenericContext context )
341
324
{
342
325
var declaring_type = ImportType ( field . DeclaringType , context ) ;
@@ -756,57 +739,316 @@ public static void CheckModule (ModuleDefinition module)
756
739
757
740
public static bool TryGetAssemblyNameReference ( this ModuleDefinition module , AssemblyNameReference name_reference , out AssemblyNameReference assembly_reference )
758
741
{
759
- var references = module . AssemblyReferences ;
742
+ return TryGetAssemblyNameReference ( module , ( AssemblyWrapper ) name_reference , out assembly_reference ) ;
743
+ }
744
+
745
+ public static bool TryGetAssemblyNameReference ( this ModuleDefinition module , SR . AssemblyName name_reference , out AssemblyNameReference assembly_reference )
746
+ {
747
+ return TryGetAssemblyNameReference ( module , ( AssemblyWrapper ) name_reference , out assembly_reference ) ;
748
+ }
760
749
761
- for ( int i = 0 ; i < references . Count ; i ++ ) {
762
- var reference = references [ i ] ;
763
- if ( ! Equals ( name_reference , reference ) )
764
- continue ;
750
+ static bool TryGetAssemblyNameReference ( this ModuleDefinition module , AssemblyWrapper name_reference , out AssemblyNameReference assembly_reference )
751
+ {
752
+ // Try to resolve the assembly using direct reference first
753
+ if ( module . TryGetDirectAssemblyNameReference ( name_reference , out assembly_reference ) ) {
754
+ return true ;
755
+ }
756
+
757
+ // If direct resolution fails, try to resolve using forwarded types
758
+ if ( module . TryGetForwardedAssemblyNameReference ( name_reference , out assembly_reference , new HashSet < string > ( ) ) ) {
759
+ return true ;
760
+ }
765
761
766
- assembly_reference = reference ;
762
+ // As a fallback, if the assembly is still unresolved,
763
+ // check if it could be a system assembly like 'System.Private.CoreLib',
764
+ // which can be safely mapped to 'System.Runtime' in certain .NET platforms.
765
+ // This handles the internal details of .NET Core and .NET 5+,
766
+ // where 'System.Private.CoreLib' is the core library but it is not referenceable
767
+ // and 'System.Runtime' is the referenceable contract assembly.
768
+ if ( module . TryGetSystemAssemblyNameReference ( name_reference , out assembly_reference ) ) {
767
769
return true ;
768
770
}
769
771
772
+ // If resolution fails, set the output reference to null
770
773
assembly_reference = null ;
771
774
return false ;
772
775
}
773
776
774
- static bool Equals ( byte [ ] a , byte [ ] b )
777
+ static bool TryGetDirectAssemblyNameReference ( this ModuleDefinition module , AssemblyWrapper name_reference , out AssemblyNameReference assembly_reference )
775
778
{
776
- if ( ReferenceEquals ( a , b ) )
777
- return true ;
778
- if ( a == null )
779
- return false ;
780
- if ( a . Length != b . Length )
781
- return false ;
782
- for ( int i = 0 ; i < a . Length ; i ++ )
783
- if ( a [ i ] != b [ i ] )
784
- return false ;
785
- return true ;
779
+ // Check each assembly reference in the module for a match by full name
780
+ foreach ( var reference in module . AssemblyReferences ) {
781
+ if ( reference . FullName == name_reference . FullName ) {
782
+ assembly_reference = reference ;
783
+ return true ;
784
+ }
785
+ }
786
+
787
+ // If no direct reference is found, set the output reference to null
788
+ assembly_reference = null ;
789
+ return false ;
786
790
}
787
791
788
- static bool Equals < T > ( T a , T b ) where T : class , IEquatable < T >
792
+ static bool TryGetForwardedAssemblyNameReference (
793
+ this ModuleDefinition module ,
794
+ AssemblyWrapper name_reference ,
795
+ out AssemblyNameReference assembly_reference ,
796
+ HashSet < string > checked_assemblies )
789
797
{
790
- if ( ReferenceEquals ( a , b ) )
791
- return true ;
792
- if ( a == null )
793
- return false ;
794
- return a . Equals ( b ) ;
798
+ // Initialize the output parameter to null
799
+ assembly_reference = null ;
800
+
801
+ // Iterate through all assembly references
802
+ foreach ( var asm_ref in module . AssemblyReferences ) {
803
+ if ( ! checked_assemblies . Add ( asm_ref . FullName ) )
804
+ continue ;
805
+
806
+ AssemblyDefinition resolved_assembly ;
807
+ try {
808
+ // Attempt to resolve the assembly reference
809
+ resolved_assembly = module . AssemblyResolver . Resolve ( asm_ref ) ;
810
+ }
811
+ catch ( AssemblyResolutionException ) {
812
+ // Skip the assembly if resolution fails
813
+ continue ;
814
+ }
815
+
816
+ // Check exported types for type forwarding within the assembly
817
+ foreach ( var module_def in resolved_assembly . Modules ) {
818
+ foreach ( var exported_type in module_def . ExportedTypes ) {
819
+ // Check if the exported type has a scope that matches the target assembly name
820
+ var scope = exported_type . Scope as AssemblyNameReference ;
821
+ if ( scope == null )
822
+ continue ;
823
+
824
+ if ( ! checked_assemblies . Add ( scope . FullName ) )
825
+ continue ;
826
+
827
+ if ( AssemblyWrapper . Equals ( scope , name_reference ) ) {
828
+ // If a match is found, return the assembly reference from which the type was forwarded
829
+ assembly_reference = asm_ref ;
830
+ return true ;
831
+ } else {
832
+ if ( TryGetForwardedAssemblyNameReference ( module , ( AssemblyWrapper ) scope , out assembly_reference , checked_assemblies ) )
833
+ return true ;
834
+ }
835
+ }
836
+ }
837
+ }
838
+
839
+ return false ;
795
840
}
796
841
797
- static bool Equals ( AssemblyNameReference a , AssemblyNameReference b )
842
+ static bool TryGetSystemAssemblyNameReference ( this ModuleDefinition module , AssemblyWrapper name_reference , out AssemblyNameReference assembly_reference )
798
843
{
799
- if ( ReferenceEquals ( a , b ) )
800
- return true ;
801
- if ( a . Name != b . Name )
844
+ assembly_reference = null ;
845
+
846
+ var possible_system_assemblies = new [ ] {
847
+ "System.Runtime" , // The main system assembly for .NET Core and .NET 5+
848
+ "mscorlib" , // The main system assembly for the .NET Framework
849
+ "netstandard" , // The pseudo-assembly for .NET Standard API surface
850
+
851
+ // Additional potential system assemblies used in specific contexts:
852
+ "System.Private.CoreLib" , // The implementation of the BCL in .NET Core and .NET 5+
853
+ } ;
854
+
855
+ var core_libs = new List < AssemblyNameReference > ( ) ;
856
+ foreach ( var asm_ref in module . AssemblyReferences ) {
857
+ foreach ( var possible_system_assembly in possible_system_assemblies ) {
858
+ if ( string . Equals ( asm_ref . Name , possible_system_assembly , StringComparison . Ordinal ) ) {
859
+ core_libs . Add ( asm_ref ) ;
860
+ break ;
861
+ }
862
+ }
863
+ }
864
+
865
+ var possible_core_lib = false ;
866
+ foreach ( var possible_system_assembly in possible_system_assemblies ) {
867
+ if ( string . Equals ( name_reference . Name , possible_system_assembly , StringComparison . Ordinal ) ) {
868
+ possible_core_lib = true ;
869
+ break ;
870
+ }
871
+ }
872
+
873
+ if ( ! possible_core_lib )
802
874
return false ;
803
- if ( ! Equals ( a . Version , b . Version ) )
875
+
876
+ if ( core_libs . Count != 1 )
804
877
return false ;
805
- if ( a . Culture != b . Culture )
878
+
879
+ var core_lib = core_libs [ 0 ] ;
880
+ AssemblyDefinition resolved_core_lib ;
881
+
882
+ try {
883
+ resolved_core_lib = module . AssemblyResolver . Resolve ( name_reference . GetAssemblyNameReference ( ) ) ;
884
+ }
885
+ catch ( AssemblyResolutionException ) {
806
886
return false ;
807
- if ( ! Equals ( a . PublicKeyToken , b . PublicKeyToken ) )
887
+ }
888
+
889
+ if ( resolved_core_lib == null )
808
890
return false ;
809
- return true ;
891
+
892
+ foreach ( var module_def in resolved_core_lib . Modules ) {
893
+ if ( module_def . GetType ( typeof ( object ) . FullName ) != null ) {
894
+ assembly_reference = core_lib ;
895
+ return true ;
896
+ }
897
+
898
+ foreach ( var exported_type in module_def . ExportedTypes ) {
899
+ if ( string . Equals ( exported_type . FullName , typeof ( object ) . FullName , StringComparison . Ordinal ) ) {
900
+
901
+ var scope = exported_type . Scope as AssemblyNameReference ;
902
+ if ( scope != null ) {
903
+ foreach ( var possible_system_assembly in possible_system_assemblies ) {
904
+ if ( string . Equals ( scope . Name , possible_system_assembly , StringComparison . Ordinal ) ) {
905
+ assembly_reference = core_lib ;
906
+ return true ;
907
+ }
908
+ }
909
+ }
910
+ }
911
+ }
912
+ }
913
+
914
+ return false ;
915
+ }
916
+
917
+ sealed class AssemblyWrapper {
918
+ private readonly SR . AssemblyName assembly_name ;
919
+ private readonly AssemblyNameReference assembly_name_reference ;
920
+
921
+ public AssemblyWrapper ( SR . AssemblyName assembly_name )
922
+ {
923
+ CheckName ( assembly_name ) ;
924
+ this . assembly_name = assembly_name ;
925
+ }
926
+
927
+ public AssemblyWrapper ( AssemblyNameReference assembly_name_reference )
928
+ {
929
+ CheckName ( assembly_name_reference ) ;
930
+ this . assembly_name_reference = assembly_name_reference ;
931
+ }
932
+
933
+ public string FullName {
934
+ get {
935
+ if ( assembly_name == null ) {
936
+ return assembly_name_reference . FullName ;
937
+ } else {
938
+ return assembly_name . FullName ;
939
+ }
940
+ }
941
+ }
942
+
943
+ public string Name {
944
+ get {
945
+ if ( assembly_name == null ) {
946
+ return assembly_name_reference . Name ;
947
+ } else {
948
+ return assembly_name . Name ;
949
+ }
950
+ }
951
+ }
952
+
953
+ public Version Version {
954
+ get {
955
+ if ( assembly_name == null ) {
956
+ return assembly_name_reference . Version ;
957
+ } else {
958
+ return assembly_name . Version ;
959
+ }
960
+ }
961
+ }
962
+
963
+ public byte [ ] PublicKeyToken {
964
+ get {
965
+ if ( assembly_name == null ) {
966
+ return assembly_name_reference . PublicKeyToken ;
967
+ } else {
968
+ return assembly_name . GetPublicKeyToken ( ) ;
969
+ }
970
+ }
971
+ }
972
+
973
+ public string Culture {
974
+ get {
975
+ if ( assembly_name == null ) {
976
+ return assembly_name_reference . Culture ;
977
+ } else {
978
+ return assembly_name . CultureInfo . Name ;
979
+ }
980
+ }
981
+ }
982
+
983
+ public AssemblyNameReference GetAssemblyNameReference ( )
984
+ {
985
+ if ( this . assembly_name != null ) {
986
+ return new AssemblyNameReference ( this . assembly_name . Name , this . assembly_name . Version ) {
987
+ PublicKeyToken = this . assembly_name . GetPublicKeyToken ( ) ,
988
+ Culture = this . assembly_name . CultureInfo . Name ,
989
+ HashAlgorithm = ( AssemblyHashAlgorithm ) this . assembly_name . HashAlgorithm ,
990
+ } ;
991
+ } else {
992
+ return this . assembly_name_reference ;
993
+ }
994
+ }
995
+
996
+ public override string ToString ( )
997
+ {
998
+ return this . Name ;
999
+ }
1000
+
1001
+ public static bool Equals ( AssemblyWrapper a , AssemblyWrapper b )
1002
+ {
1003
+ if ( ReferenceEquals ( a , b ) )
1004
+ return true ;
1005
+ if ( a . assembly_name != null && ReferenceEquals ( a . assembly_name , b . assembly_name ) )
1006
+ return true ;
1007
+ if ( a . assembly_name_reference != null && ReferenceEquals ( a . assembly_name_reference , b . assembly_name_reference ) )
1008
+ return true ;
1009
+ if ( a . Name != b . Name )
1010
+ return false ;
1011
+ if ( ! Equals ( a . Version , b . Version ) )
1012
+ return false ;
1013
+ if ( a . Culture != b . Culture )
1014
+ return false ;
1015
+ if ( ! Equals ( a . PublicKeyToken , b . PublicKeyToken ) )
1016
+ return false ;
1017
+ return true ;
1018
+ }
1019
+
1020
+ static bool Equals ( byte [ ] a , byte [ ] b )
1021
+ {
1022
+ if ( ReferenceEquals ( a , b ) )
1023
+ return true ;
1024
+ if ( a == null )
1025
+ return false ;
1026
+ if ( a . Length != b . Length )
1027
+ return false ;
1028
+ for ( int i = 0 ; i < a . Length ; i ++ )
1029
+ if ( a [ i ] != b [ i ] )
1030
+ return false ;
1031
+ return true ;
1032
+ }
1033
+
1034
+ static bool Equals < T > ( T a , T b ) where T : class , IEquatable < T >
1035
+ {
1036
+ if ( ReferenceEquals ( a , b ) )
1037
+ return true ;
1038
+ if ( a == null )
1039
+ return false ;
1040
+ return a . Equals ( b ) ;
1041
+ }
1042
+
1043
+ public static explicit operator AssemblyWrapper ( SR . AssemblyName assembly_name )
1044
+ {
1045
+ return new AssemblyWrapper ( assembly_name ) ;
1046
+ }
1047
+
1048
+ public static explicit operator AssemblyWrapper ( AssemblyNameReference assembly_name_reference )
1049
+ {
1050
+ return new AssemblyWrapper ( assembly_name_reference ) ;
1051
+ }
810
1052
}
811
1053
}
812
1054
}
0 commit comments