From dc40032a6a6f0b17775eb01cde722e565f5cf37d Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 11 Sep 2024 09:21:27 -0700 Subject: [PATCH 01/16] Remove `BaseDomain` (#107652) The `BaseDomain` concept is no longer useful now that we don't have shared domains or multiple app domains. It has been gutted enough and usages moved to directly use `AppDomain` or `SystemDomain` that it can just be removed now. With this change, `AppDomain` and `SystemDomain` are separate classes with no shared base. --- src/coreclr/debug/daccess/dacfn.cpp | 7 +-- src/coreclr/inc/daccess.h | 22 ++++----- src/coreclr/inc/vptr_list.h | 3 -- src/coreclr/utilcode/ex.cpp | 2 +- src/coreclr/utilcode/loaderheap.cpp | 2 +- src/coreclr/vm/appdomain.cpp | 4 +- src/coreclr/vm/appdomain.hpp | 71 +++------------------------ src/coreclr/vm/arm/cgencpu.h | 1 - src/coreclr/vm/assembly.hpp | 4 -- src/coreclr/vm/ceeload.h | 1 - src/coreclr/vm/common.h | 3 +- src/coreclr/vm/contractimpl.h | 1 - src/coreclr/vm/genericdict.h | 3 +- src/coreclr/vm/i386/cgencpu.h | 1 - src/coreclr/vm/ilstubcache.cpp | 18 ++----- src/coreclr/vm/instmethhash.h | 2 +- src/coreclr/vm/multicorejitplayer.cpp | 2 +- src/coreclr/vm/object.h | 1 - src/coreclr/vm/typehandle.h | 1 - src/coreclr/vm/typehash.h | 5 +- 20 files changed, 35 insertions(+), 119 deletions(-) diff --git a/src/coreclr/debug/daccess/dacfn.cpp b/src/coreclr/debug/daccess/dacfn.cpp index 07cb785ee4ae1..8077463c8e234 100644 --- a/src/coreclr/debug/daccess/dacfn.cpp +++ b/src/coreclr/debug/daccess/dacfn.cpp @@ -616,9 +616,10 @@ DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx) // Sanity check that the object we're returning is big enough to fill the PTR type it's being // accessed with. // If this is not true, it means the type being marshalled isn't a sub-type (or the same type) - // as the PTR type it's being used as. For example, trying to marshal an instance of a SystemDomain - // object into a PTR_AppDomain will cause this ASSERT to fire (because both SystemDomain and AppDomain - // derived from BaseDomain, and SystemDomain is smaller than AppDomain). + // as the PTR type it's being used as. For example, trying to marshal an AssemblyLoaderAllocator + // into a PTR_GlobalLoaderAllocator will cause this ASSERT to fire (because AssemblyLoaderAllocator + // and GlobalLoaderAllocator derived from LoaderAllocator and AssemblyLoaderAllocator is smaller + // than GlobalLoaderAllocator). _ASSERTE_MSG(size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small"); inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_VPTR); diff --git a/src/coreclr/inc/daccess.h b/src/coreclr/inc/daccess.h index 3c6a1b85a3511..7bc2baed536e3 100644 --- a/src/coreclr/inc/daccess.h +++ b/src/coreclr/inc/daccess.h @@ -282,9 +282,9 @@ // // extern ThreadStore* g_pThreadStore; // ThreadStore* g_pThreadStore = &StaticStore; -// class SystemDomain : public BaseDomain { +// class CodeVersionManager { // ... -// ArrayListStatic m_appDomainIndexList; +// static BOOL s_HasNonDefaultILVersions; // ... // } // @@ -304,9 +304,9 @@ // GPTR_DECL(ThreadStore, g_pThreadStore); // GPTR_IMPL_INIT(ThreadStore, g_pThreadStore, &StaticStore); // -// class SystemDomain : public BaseDomain { +// class CodeVersionManager { // ... -// SVAL_DECL(ArrayListStatic; m_appDomainIndexList); +// SVAL_DECL(BOOL, s_HasNonDefaultILVersions); // ... // } // @@ -994,7 +994,7 @@ class __DPtrBase : public __TPtrBase __DPtrBase() = default; explicit __DPtrBase(__TPtrBase ptr) : __TPtrBase(ptr.GetAddr()) {} - + // construct const from non-const __DPtrBase(__DPtrBase::type, DPtrTemplate> const & rhs) : __DPtrBase(rhs.GetAddr()) {} @@ -2205,9 +2205,7 @@ public: name(int dummy) : base(dummy) {} // helper macro to make the vtables unique for DAC #define VPTR_UNIQUE(unique) virtual int MakeVTableUniqueForDAC() { return unique; } -#define VPTR_UNIQUE_BaseDomain (100000) -#define VPTR_UNIQUE_SystemDomain (VPTR_UNIQUE_BaseDomain + 1) -#define VPTR_UNIQUE_ComMethodFrame (VPTR_UNIQUE_SystemDomain + 1) +#define VPTR_UNIQUE_ComMethodFrame (100000) #define VPTR_UNIQUE_RedirectedThreadFrame (VPTR_UNIQUE_ComMethodFrame + 1) #define VPTR_UNIQUE_HijackFrame (VPTR_UNIQUE_RedirectedThreadFrame + 1) @@ -2319,10 +2317,10 @@ public: name(int dummy) : base(dummy) {} // pMD = dac_cast(pInstMD) // // - (D|V)PTR of one encapsulated pointer type to a (D|V)PTR of -// another type, i.e., PTR_AppDomain <-> PTR_BaseDomain -// Syntax: with PTR_AppDomain pAD, PTR_BaseDomain pBD -// dac_cast(pBD) -// dac_cast(pAD) +// another type, i.e., PTR_Module <-> PTR_ModuleBase +// Syntax: with PTR_Module pModule, PTR_Module pModuleBase +// dac_cast(pModuleBase) +// dac_cast(pModule) // // Example comparisons of some old and new syntax, where // h is a host pointer, such as "Foo *h;" diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index de8b5bfc9d190..8150147bfa2cb 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -21,9 +21,6 @@ VPTR_CLASS(EditAndContinueModule) VPTR_CLASS(Module) VPTR_CLASS(ReflectionModule) -VPTR_CLASS(AppDomain) -VPTR_CLASS(SystemDomain) - VPTR_CLASS(PrecodeStubManager) VPTR_CLASS(StubLinkStubManager) VPTR_CLASS(ThePreStubManager) diff --git a/src/coreclr/utilcode/ex.cpp b/src/coreclr/utilcode/ex.cpp index 8197e4f0ef72c..986f9b95d1343 100644 --- a/src/coreclr/utilcode/ex.cpp +++ b/src/coreclr/utilcode/ex.cpp @@ -174,7 +174,7 @@ BOOL Exception::IsTerminal() GC_NOTRIGGER; NOTHROW; - // CLRException::GetHR() can eventually call BaseDomain::CreateHandle(), + // CLRException::GetHR() can eventually call AppDomain::CreateHandle(), // which can indirectly cause a lock if we get a miss in the handle table // cache (TableCacheMissOnAlloc). Since CLRException::GetHR() is virtual, // SCAN won't find this for you (though 40 minutes of one of the sql stress diff --git a/src/coreclr/utilcode/loaderheap.cpp b/src/coreclr/utilcode/loaderheap.cpp index 252f7afb237e9..9cbda2a524456 100644 --- a/src/coreclr/utilcode/loaderheap.cpp +++ b/src/coreclr/utilcode/loaderheap.cpp @@ -337,7 +337,7 @@ RangeList::RangeListBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) _ASSERTE( size < UINT32_MAX ); // ranges should be less than 4gig! // We can't be sure this entire range is mapped. For example, the code:StubLinkStubManager - // keeps track of all ranges in the code:BaseDomain::m_pStubHeap LoaderHeap, and + // keeps track of all ranges in the code:LoaderAllocator::m_pStubHeap LoaderHeap, and // code:LoaderHeap::UnlockedReservePages adds a range for the entire reserved region, instead // of updating the RangeList when pages are committed. But in that case, the committed region of // memory will be enumerated by the LoaderHeap anyway, so it's OK if this fails diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 157f32ebbd437..c53e4a1c20ec8 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -4420,7 +4420,7 @@ AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis) if (enumThis) { //sizeof(AppDomain) == 0xeb0 - DAC_ENUM_VTHIS(); + DAC_ENUM_DTHIS(); EMEM_OUT(("MEM: %p AppDomain\n", dac_cast(this))); } @@ -4451,7 +4451,7 @@ SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis) SUPPORTS_DAC; if (enumThis) { - DAC_ENUM_VTHIS(); + DAC_ENUM_DTHIS(); EMEM_OUT(("MEM: %p SystemAppomain\n", dac_cast(this))); } diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 5f8ad63a07113..7197f4827199a 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -35,7 +35,6 @@ #include "codeversion.h" -class BaseDomain; class SystemDomain; class AppDomain; class GlobalStringLiteralMap; @@ -435,47 +434,6 @@ class LoadLevelLimiter final __newLimit.Activate(); \ __newLimit.SetLoadLevel(newLimit); -// A BaseDomain much basic information in a code:AppDomain including -// -// * code:#AppdomainHeaps - Heaps for any data structures that will be freed on appdomain unload -// -class BaseDomain -{ - friend class Assembly; - friend class AssemblySpec; - friend class AppDomain; - - VPTR_BASE_VTABLE_CLASS(BaseDomain) - VPTR_UNIQUE(VPTR_UNIQUE_BaseDomain) - -public: - - class AssemblyIterator; - friend class AssemblyIterator; - - //**************************************************************************************** - // - // Initialization/shutdown routines for every instance of an BaseDomain. - - BaseDomain() = default; - virtual ~BaseDomain() {} - - virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; } - - virtual PTR_AppDomain AsAppDomain() - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Not an AppDomain"); - return NULL; - } - -#ifdef DACCESS_COMPILE -public: - virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis) = 0; -#endif - -}; // class BaseDomain - enum { ATTACH_ASSEMBLY_LOAD = 0x1, @@ -687,25 +645,17 @@ const DWORD DefaultADID = 1; // Threads are always running in the context of a particular AppDomain. See // file:threads.h#RuntimeThreadLocals for more details. // -// see code:BaseDomain for much of the meat of a AppDomain (heaps locks, etc) // * code:AppDomain.m_Assemblies - is a list of code:Assembly in the appdomain // -class AppDomain : public BaseDomain +class AppDomain final { - friend class SystemDomain; - friend class AssemblyNative; - friend class AssemblySpec; - friend class ClassLoader; - friend class ThreadNative; + friend struct _DacGlobals; friend class ClrDataAccess; - friend class CheckAsmOffsets; - - VPTR_VTABLE_CLASS(AppDomain, BaseDomain) public: #ifndef DACCESS_COMPILE AppDomain(); - virtual ~AppDomain(); + ~AppDomain(); static void Create(); #endif @@ -730,9 +680,6 @@ class AppDomain : public BaseDomain // final assembly cleanup void ShutdownFreeLoaderAllocators(); - virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; } - virtual PTR_AppDomain AsAppDomain() { LIMITED_METHOD_CONTRACT; return dac_cast(this); } - PTR_LoaderAllocator GetLoaderAllocator(); STRINGREF *IsStringInterned(STRINGREF *pString); @@ -1694,7 +1641,7 @@ class AppDomain : public BaseDomain #ifdef DACCESS_COMPILE public: - virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis); #endif @@ -1731,15 +1678,13 @@ class AppDomain : public BaseDomain // Just a ref holder typedef ReleaseHolder AppDomainRefHolder; -typedef VPTR(class SystemDomain) PTR_SystemDomain; +typedef DPTR(class SystemDomain) PTR_SystemDomain; -class SystemDomain : public BaseDomain +class SystemDomain final { + friend struct _DacGlobals; friend class ClrDataAccess; - VPTR_VTABLE_CLASS(SystemDomain, BaseDomain) - VPTR_UNIQUE(VPTR_UNIQUE_SystemDomain) - public: static PTR_LoaderAllocator GetGlobalLoaderAllocator(); @@ -2062,7 +2007,7 @@ inline static BOOL IsUnderDomainLock() { LIMITED_METHOD_CONTRACT; return m_Syste #ifdef DACCESS_COMPILE public: - virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis); #endif diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h index c98d94ad6affa..e5d6ef97e6167 100644 --- a/src/coreclr/vm/arm/cgencpu.h +++ b/src/coreclr/vm/arm/cgencpu.h @@ -47,7 +47,6 @@ class FramedMethodFrame; class Module; struct DeclActionInfo; class ComCallMethodDesc; -class BaseDomain; class ZapNode; struct ArgLocDesc; diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index 76b834c2683f6..c0b56d9cd21c2 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -23,10 +23,8 @@ #include "cordbpriv.h" #include "assemblyspec.hpp" -class BaseDomain; class AppDomain; class DomainAssembly; -class DomainModule; class SystemDomain; class ClassLoader; class AssemblyNative; @@ -45,13 +43,11 @@ class FriendAssemblyDescriptor; // class Assembly { - friend class BaseDomain; friend class SystemDomain; friend class ClassLoader; friend class AssemblyNative; friend class AssemblySpec; friend class NDirect; - friend class AssemblyNameNative; friend class ClrDataAccess; private: diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index decc73bb336f9..e433e15174ca1 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -52,7 +52,6 @@ class EEStringData; class MethodDescChunk; class SigTypeContext; class Assembly; -class BaseDomain; class AppDomain; class SystemDomain; class Module; diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 92e9c5f1d58a6..0cac88530530b 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -101,14 +101,13 @@ using std::min; typedef VPTR(class LoaderAllocator) PTR_LoaderAllocator; typedef DPTR(PTR_LoaderAllocator) PTR_PTR_LoaderAllocator; -typedef VPTR(class AppDomain) PTR_AppDomain; +typedef DPTR(class AppDomain) PTR_AppDomain; typedef DPTR(class ArrayBase) PTR_ArrayBase; typedef DPTR(class Assembly) PTR_Assembly; typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject; typedef DPTR(class AssemblyLoadContextBaseObject) PTR_AssemblyLoadContextBaseObject; typedef DPTR(class AssemblyBinder) PTR_AssemblyBinder; typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject; -typedef VPTR(class BaseDomain) PTR_BaseDomain; typedef DPTR(class ClassLoader) PTR_ClassLoader; typedef DPTR(class ComCallMethodDesc) PTR_ComCallMethodDesc; typedef DPTR(class CLRToCOMCallMethodDesc) PTR_CLRToCOMCallMethodDesc; diff --git a/src/coreclr/vm/contractimpl.h b/src/coreclr/vm/contractimpl.h index 786139745dfde..f8d7d81856f46 100644 --- a/src/coreclr/vm/contractimpl.h +++ b/src/coreclr/vm/contractimpl.h @@ -120,7 +120,6 @@ class DispatchMapTypeID struct DispatchTokenFat { friend struct DispatchToken; - friend class BaseDomain; private: UINT32 m_typeId; diff --git a/src/coreclr/vm/genericdict.h b/src/coreclr/vm/genericdict.h index 277250fdae4fe..3fa28e0a9c9d0 100644 --- a/src/coreclr/vm/genericdict.h +++ b/src/coreclr/vm/genericdict.h @@ -45,7 +45,6 @@ class TypeHandleList; class Module; -class BaseDomain; class SigTypeContext; class SigBuilder; @@ -182,7 +181,7 @@ class DictionaryLayout class Dictionary { private: - // First N entries are generic instantiations arguments. + // First N entries are generic instantiations arguments. // The rest of the open array are normal pointers (no optional indirection) and may be NULL. DictionaryEntry m_pEntries[1]; diff --git a/src/coreclr/vm/i386/cgencpu.h b/src/coreclr/vm/i386/cgencpu.h index 05013a5018512..f5783f7350301 100644 --- a/src/coreclr/vm/i386/cgencpu.h +++ b/src/coreclr/vm/i386/cgencpu.h @@ -29,7 +29,6 @@ class MethodDesc; class FramedMethodFrame; class Module; class ComCallMethodDesc; -class BaseDomain; // CPU-dependent functions Stub * GenerateInitPInvokeFrameHelper(); diff --git a/src/coreclr/vm/ilstubcache.cpp b/src/coreclr/vm/ilstubcache.cpp index e16ddbc0f3b2c..9935471e7d5f4 100644 --- a/src/coreclr/vm/ilstubcache.cpp +++ b/src/coreclr/vm/ilstubcache.cpp @@ -447,9 +447,9 @@ MethodDesc* ILStubCache::InsertStubMethodDesc(MethodDesc *pMD, ILStubHashBlob* p // // JIT'ed IL stubs // -// - The ILStubCache is per-BaseDomain +// - The ILStubCache is per-LoaderAllocator // -// - Each BaseDomain's ILStubCache will lazily create a "minimal MethodTable" to +// - Each LoaderAllocator's ILStubCache will lazily create a "minimal MethodTable" to // serve as the home for IL stub MethodDescs // // - The created MethodTables will use the Module belonging to one of the @@ -463,10 +463,7 @@ MethodDesc* ILStubCache::InsertStubMethodDesc(MethodDesc *pMD, ILStubHashBlob* p // // It's important to point out that the Module we latch onto here has no knowledge // of the MethodTable that we've just "added" to it. There only exists a "back -// pointer" to the Module from the MethodTable itself. So we're really only using -// that module to answer the question of what BaseDomain the MethodTable lives in. -// So as long as the BaseDomain for that module is the same as the BaseDomain the -// ILStubCache lives in, I think we have a fairly consistent story here. +// pointer" to the Module from the MethodTable itself. // // We're relying on the fact that a VASigCookie may only mention types within the // corresponding module used to qualify the signature and the fact that interop @@ -475,14 +472,7 @@ MethodDesc* ILStubCache::InsertStubMethodDesc(MethodDesc *pMD, ILStubHashBlob* p // ELEMENT_TYPE_INTERNAL, which may refer to any type. // // We can only access E_T_INTERNAL through LCG, which does not permit referring -// to types in other BaseDomains. -// -// -// Places for improvement: -// -// - allow NGEN'ing of CALLI pinvoke and vararg pinvoke -// -// - pre-populate the per-BaseDomain cache with IL stubs from NGEN'ed image +// to types in other AppDomains. // MethodDesc* ILStubCache::GetStubMethodDesc( diff --git a/src/coreclr/vm/instmethhash.h b/src/coreclr/vm/instmethhash.h index 153bbe4740846..e784408863704 100644 --- a/src/coreclr/vm/instmethhash.h +++ b/src/coreclr/vm/instmethhash.h @@ -26,7 +26,7 @@ class AllocMemTracker; // Each persisted Module has an InstMethodHashTable used for such methods that // were ngen'ed into that module. See ceeload.hpp for more information about ngen modules. // -// Methods created at runtime are placed in an InstMethHashTable in BaseDomain. +// Methods created at runtime are placed in an InstMethHashTable in Module. // // Keys are always derivable from the data stored in the table (MethodDesc) // diff --git a/src/coreclr/vm/multicorejitplayer.cpp b/src/coreclr/vm/multicorejitplayer.cpp index 76659b255229e..fcc4a46a33fcf 100644 --- a/src/coreclr/vm/multicorejitplayer.cpp +++ b/src/coreclr/vm/multicorejitplayer.cpp @@ -45,7 +45,7 @@ void MulticoreJitCodeStorage::Init() CONTRACTL { THROWS; - MODE_ANY; // called from BaseDomain::Init which is MODE_ANY + MODE_ANY; // called from SystemDomain::Attach which is MODE_ANY } CONTRACTL_END; diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index 6c17bf93c800e..91e38c5ac9496 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -77,7 +77,6 @@ void ErectWriteBarrierForMT(MethodTable **dst, MethodTable *ref); class MethodTable; class Thread; -class BaseDomain; class Assembly; class DomainAssembly; class AssemblyNative; diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 9e624629b72f6..49339467faea5 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -27,7 +27,6 @@ class MethodTable; class EEClass; class Module; class Assembly; -class BaseDomain; class MethodDesc; class TypeKey; class TypeHandleList; diff --git a/src/coreclr/vm/typehash.h b/src/coreclr/vm/typehash.h index 8afe7dff89a3b..86a97b888dd2c 100644 --- a/src/coreclr/vm/typehash.h +++ b/src/coreclr/vm/typehash.h @@ -15,10 +15,7 @@ // This hash table is used by class loaders to look up constructed types: // arrays, pointers and instantiations of user-defined generic types. // -// Each persisted module structure has an EETypeHashTable used for constructed types that -// were ngen'ed into that module. See ceeload.hpp for more information about ngen modules. -// -// Types created at runtime are placed in an EETypeHashTable in BaseDomain. +// Types created at runtime are placed in an EETypeHashTable in Module. // // Keys are derivable from the data stored in the table (TypeHandle) // - for an instantiated type, the typedef module, typedef token, and instantiation From 60fc78e80e2faac520db5249890f6c61f031c2de Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 11 Sep 2024 17:59:12 +0100 Subject: [PATCH 02/16] Disallow types with property names conflicting with metadata. (#106460) --- .../src/Resources/Strings.resx | 3 + .../Metadata/JsonPropertyInfo.cs | 15 ++- .../Metadata/PolymorphicTypeResolver.cs | 42 +++++--- .../Text/Json/ThrowHelper.Serialization.cs | 6 ++ .../ReferenceHandlerTests.cs | 72 ++++++++++++++ .../Serialization/ReferenceHandlerTests.cs | 8 ++ .../Serialization/PolymorphicTests.cs | 98 +++++++++++++++++++ 7 files changed, 228 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index 8b2b0e0ad0419..8a571e258a4f6 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -662,6 +662,9 @@ The metadata property names '$id', '$ref', and '$values' are reserved and cannot be used as custom type discriminator property names. + + The type '{0}' contains property '{1}' that conflicts with an existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute. + Polymorphic configuration for type '{0}' should specify at least one derived type. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs index 4077c89fe9789..29e11071fb7eb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs @@ -443,7 +443,7 @@ internal void Configure() } else { - CacheNameAsUtf8BytesAndEscapedNameSection(); + ValidateAndCachePropertyName(); } if (IsRequired) @@ -472,10 +472,21 @@ internal void Configure() [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] internal abstract void DetermineReflectionPropertyAccessors(MemberInfo memberInfo, bool useNonPublicAccessors); - private void CacheNameAsUtf8BytesAndEscapedNameSection() + private void ValidateAndCachePropertyName() { Debug.Assert(Name != null); + if (Options.ReferenceHandlingStrategy is ReferenceHandlingStrategy.Preserve && + this is { DeclaringType.IsValueType: false, IsIgnored: false, IsExtensionData: false } && + Name is JsonSerializer.IdPropertyName or JsonSerializer.RefPropertyName) + { + // Validate potential conflicts with reference preservation metadata property names. + // Conflicts with polymorphic type discriminators are contextual and need to be + // handled separately by the PolymorphicTypeResolver type. + + ThrowHelper.ThrowInvalidOperationException_PropertyConflictsWithMetadataPropertyName(DeclaringType, Name); + } + NameAsUtf8Bytes = Encoding.UTF8.GetBytes(Name); EscapedNameSection = JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/PolymorphicTypeResolver.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/PolymorphicTypeResolver.cs index b0ed4b24a60e2..075ea31a65a38 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/PolymorphicTypeResolver.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/PolymorphicTypeResolver.cs @@ -42,16 +42,17 @@ public PolymorphicTypeResolver(JsonSerializerOptions options, JsonPolymorphismOp ThrowHelper.ThrowInvalidOperationException_DerivedTypeNotSupported(BaseType, derivedType); } - var derivedJsonTypeInfo = new DerivedJsonTypeInfo(derivedType, typeDiscriminator); + JsonTypeInfo derivedTypeInfo = options.GetTypeInfoInternal(derivedType); + DerivedJsonTypeInfo derivedTypeInfoHolder = new(typeDiscriminator, derivedTypeInfo); - if (!_typeToDiscriminatorId.TryAdd(derivedType, derivedJsonTypeInfo)) + if (!_typeToDiscriminatorId.TryAdd(derivedType, derivedTypeInfoHolder)) { ThrowHelper.ThrowInvalidOperationException_DerivedTypeIsAlreadySpecified(BaseType, derivedType); } if (typeDiscriminator is not null) { - if (!(_discriminatorIdtoType ??= new()).TryAdd(typeDiscriminator, derivedJsonTypeInfo)) + if (!(_discriminatorIdtoType ??= new()).TryAdd(typeDiscriminator, derivedTypeInfoHolder)) { ThrowHelper.ThrowInvalidOperationException_TypeDicriminatorIdIsAlreadySpecified(BaseType, typeDiscriminator); } @@ -69,6 +70,8 @@ public PolymorphicTypeResolver(JsonSerializerOptions options, JsonPolymorphismOp if (UsesTypeDiscriminators) { + Debug.Assert(_discriminatorIdtoType != null, "Discriminator index must have been populated."); + if (!converterCanHaveMetadata) { ThrowHelper.ThrowNotSupportedException_BaseConverterDoesNotSupportMetadata(BaseType); @@ -88,6 +91,21 @@ public PolymorphicTypeResolver(JsonSerializerOptions options, JsonPolymorphismOp CustomTypeDiscriminatorPropertyNameUtf8 = utf8EncodedName; CustomTypeDiscriminatorPropertyNameJsonEncoded = JsonEncodedText.Encode(propertyName, options.Encoder); } + + // Check if the discriminator property name conflicts with any derived property names. + foreach (DerivedJsonTypeInfo derivedTypeInfo in _discriminatorIdtoType.Values) + { + if (derivedTypeInfo.JsonTypeInfo.Kind is JsonTypeInfoKind.Object) + { + foreach (JsonPropertyInfo property in derivedTypeInfo.JsonTypeInfo.Properties) + { + if (property is { IsIgnored: false, IsExtensionData: false } && property.Name == propertyName) + { + ThrowHelper.ThrowInvalidOperationException_PropertyConflictsWithMetadataPropertyName(derivedTypeInfo.JsonTypeInfo.Type, propertyName); + } + } + } + } } } @@ -136,7 +154,7 @@ public bool TryGetDerivedJsonTypeInfo(Type runtimeType, [NotNullWhen(true)] out } else { - jsonTypeInfo = result.GetJsonTypeInfo(_options); + jsonTypeInfo = result.JsonTypeInfo; typeDiscriminator = result.TypeDiscriminator; return true; } @@ -151,7 +169,7 @@ public bool TryGetDerivedJsonTypeInfo(object typeDiscriminator, [NotNullWhen(tru if (_discriminatorIdtoType.TryGetValue(typeDiscriminator, out DerivedJsonTypeInfo? result)) { Debug.Assert(typeDiscriminator.Equals(result.TypeDiscriminator)); - jsonTypeInfo = result.GetJsonTypeInfo(_options); + jsonTypeInfo = result.JsonTypeInfo; return true; } @@ -218,7 +236,7 @@ public static bool IsSupportedDerivedType(Type baseType, Type? derivedType) => } else { - ThrowHelper.ThrowNotSupportedException_RuntimeTypeDiamondAmbiguity(BaseType, type, result.DerivedType, interfaceResult.DerivedType); + ThrowHelper.ThrowNotSupportedException_RuntimeTypeDiamondAmbiguity(BaseType, type, result.JsonTypeInfo.Type, interfaceResult.JsonTypeInfo.Type); } } } @@ -307,24 +325,20 @@ public static bool IsSupportedDerivedType(Type baseType, Type? derivedType) => } /// - /// Lazy JsonTypeInfo result holder for a derived type. + /// JsonTypeInfo result holder for a derived type. /// private sealed class DerivedJsonTypeInfo { - private volatile JsonTypeInfo? _jsonTypeInfo; - - public DerivedJsonTypeInfo(Type type, object? typeDiscriminator) + public DerivedJsonTypeInfo(object? typeDiscriminator, JsonTypeInfo derivedTypeInfo) { Debug.Assert(typeDiscriminator is null or int or string); - DerivedType = type; TypeDiscriminator = typeDiscriminator; + JsonTypeInfo = derivedTypeInfo; } - public Type DerivedType { get; } public object? TypeDiscriminator { get; } - public JsonTypeInfo GetJsonTypeInfo(JsonSerializerOptions options) - => _jsonTypeInfo ??= options.GetTypeInfoInternal(DerivedType); + public JsonTypeInfo JsonTypeInfo { get; } } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index fed9efb84d031..b93651e0cddb6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -903,6 +903,12 @@ public static void ThrowInvalidOperationException_InvalidCustomTypeDiscriminator throw new InvalidOperationException(SR.Polymorphism_InvalidCustomTypeDiscriminatorPropertyName); } + [DoesNotReturn] + public static void ThrowInvalidOperationException_PropertyConflictsWithMetadataPropertyName(Type type, string propertyName) + { + throw new InvalidOperationException(SR.Format(SR.Polymorphism_PropertyConflictsWithMetadataPropertyName, type, propertyName)); + } + [DoesNotReturn] public static void ThrowInvalidOperationException_PolymorphicTypeConfigurationDoesNotSpecifyDerivedTypes(Type baseType) { diff --git a/src/libraries/System.Text.Json/tests/Common/ReferenceHandlerTests/ReferenceHandlerTests.cs b/src/libraries/System.Text.Json/tests/Common/ReferenceHandlerTests/ReferenceHandlerTests.cs index d0db5d9c58525..c455278ea1299 100644 --- a/src/libraries/System.Text.Json/tests/Common/ReferenceHandlerTests/ReferenceHandlerTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/ReferenceHandlerTests/ReferenceHandlerTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Text.Encodings.Web; +using System.Text.Json.Nodes; using System.Threading.Tasks; using Newtonsoft.Json; using Xunit; @@ -849,5 +850,76 @@ public IEnumerator GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } + + [Theory] + [InlineData(typeof(ClassWithConflictingRefProperty), "$ref")] + [InlineData(typeof(ClassWithConflictingIdProperty), "$id")] + public async Task ClassWithConflictingMetadataProperties_ThrowsInvalidOperationException(Type type, string propertyName) + { + InvalidOperationException ex; + object value = Activator.CreateInstance(type); + + ex = Assert.Throws(() => Serializer.GetTypeInfo(type, s_serializerOptionsPreserve)); + ValidateException(ex); + + ex = await Assert.ThrowsAsync(() => Serializer.SerializeWrapper(value, type, s_serializerOptionsPreserve)); + ValidateException(ex); + + ex = await Assert.ThrowsAsync(() => Serializer.DeserializeWrapper("{}", type, s_serializerOptionsPreserve)); + ValidateException(ex); + + void ValidateException(InvalidOperationException ex) + { + Assert.Contains($"The type '{type}' contains property '{propertyName}' that conflicts with an existing metadata property name.", ex.Message); + } + } + + public class ClassWithConflictingRefProperty + { + [JsonPropertyName("$ref")] + public int Value { get; set; } + } + + public class ClassWithConflictingIdProperty + { + [JsonPropertyName("$id")] + public int Value { get; set; } + } + + [Fact] + public async Task ClassWithIgnoredConflictingProperty_Supported() + { + ClassWithIgnoredConflictingProperty value = new(); + string json = await Serializer.SerializeWrapper(value, s_serializerOptionsPreserve); + Assert.Equal("""{"$id":"1"}""", json); + + value = await Serializer.DeserializeWrapper(json, s_serializerOptionsPreserve); + Assert.NotNull(value); + } + + public class ClassWithIgnoredConflictingProperty + { + [JsonPropertyName("$id"), JsonIgnore] + public int Value { get; set; } + } + + [Fact] + public async Task ClassWithExtensionDataConflictingProperty_Supported() + { + ClassWithExtensionDataConflictingProperty value = new(); + string json = await Serializer.SerializeWrapper(value, s_serializerOptionsPreserve); + Assert.Equal("""{"$id":"1"}""", json); + + value = await Serializer.DeserializeWrapper("""{"$id":"1","extraProp":null}""", s_serializerOptionsPreserve); + Assert.NotNull(value); + Assert.Equal(1, value.Value.Count); + Assert.Contains("extraProp", value.Value); + } + + public class ClassWithExtensionDataConflictingProperty + { + [JsonPropertyName("$id"), JsonExtensionData] + public JsonObject Value { get; set; } + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ReferenceHandlerTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ReferenceHandlerTests.cs index 001ecf921c8a0..03c1ede64586f 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ReferenceHandlerTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ReferenceHandlerTests.cs @@ -135,6 +135,10 @@ public ReferenceHandlerTests_Metadata(JsonSerializerWrapper serializer) [JsonSerializable(typeof(LinkedList))] [JsonSerializable(typeof(LinkedList))] [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(ClassWithConflictingRefProperty))] + [JsonSerializable(typeof(ClassWithConflictingIdProperty))] + [JsonSerializable(typeof(ClassWithIgnoredConflictingProperty))] + [JsonSerializable(typeof(ClassWithExtensionDataConflictingProperty))] internal sealed partial class ReferenceHandlerTestsContext_Metadata : JsonSerializerContext { } @@ -273,6 +277,10 @@ public ReferenceHandlerTests_Default(JsonSerializerWrapper serializer) [JsonSerializable(typeof(LinkedList))] [JsonSerializable(typeof(LinkedList))] [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(ClassWithConflictingRefProperty))] + [JsonSerializable(typeof(ClassWithConflictingIdProperty))] + [JsonSerializable(typeof(ClassWithIgnoredConflictingProperty))] + [JsonSerializable(typeof(ClassWithExtensionDataConflictingProperty))] internal sealed partial class ReferenceHandlerTestsContext_Default : JsonSerializerContext { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.cs index 9e14737051a2e..861522b881d79 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PolymorphicTests.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Text.Json.Nodes; using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; using Xunit; @@ -577,5 +578,102 @@ class MyDerivedThing : MyThing class MyThingCollection : List { } class MyThingDictionary : Dictionary { } + + [Theory] + [InlineData(typeof(PolymorphicTypeWithConflictingPropertyNameAtBase), typeof(PolymorphicTypeWithConflictingPropertyNameAtBase.Derived))] + [InlineData(typeof(PolymorphicTypeWithConflictingPropertyNameAtDerived), typeof(PolymorphicTypeWithConflictingPropertyNameAtDerived.Derived))] + public async Task PolymorphicTypesWithConflictingPropertyNames_ThrowsInvalidOperationException(Type baseType, Type derivedType) + { + InvalidOperationException ex; + object value = Activator.CreateInstance(derivedType); + + ex = Assert.Throws(() => Serializer.GetTypeInfo(baseType)); + ValidateException(ex); + + ex = await Assert.ThrowsAsync(() => Serializer.SerializeWrapper(value, baseType)); + ValidateException(ex); + + ex = await Assert.ThrowsAsync(() => Serializer.DeserializeWrapper("{}", baseType)); + ValidateException(ex); + + void ValidateException(InvalidOperationException ex) + { + Assert.Contains($"The type '{derivedType}' contains property 'Type' that conflicts with an existing metadata property name.", ex.Message); + } + } + + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonDerivedType(typeof(Derived), nameof(Derived))] + public abstract class PolymorphicTypeWithConflictingPropertyNameAtBase + { + public string Type { get; set; } + + public class Derived : PolymorphicTypeWithConflictingPropertyNameAtBase + { + public string Name { get; set; } + } + } + + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonDerivedType(typeof(Derived), nameof(Derived))] + public abstract class PolymorphicTypeWithConflictingPropertyNameAtDerived + { + public class Derived : PolymorphicTypeWithConflictingPropertyNameAtDerived + { + public string Type { get; set; } + } + } + + [Fact] + public async Task PolymorphicTypeWithIgnoredConflictingPropertyName_Supported() + { + PolymorphicTypeWithIgnoredConflictingPropertyName value = new PolymorphicTypeWithIgnoredConflictingPropertyName.Derived(); + + JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(PolymorphicTypeWithIgnoredConflictingPropertyName)); + Assert.NotNull(typeInfo); + + string json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"Type":"Derived"}""", json); + + value = await Serializer.DeserializeWrapper(json); + Assert.IsType(value); + } + + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonDerivedType(typeof(Derived), nameof(Derived))] + public abstract class PolymorphicTypeWithIgnoredConflictingPropertyName + { + [JsonIgnore] + public string Type { get; set; } + + public class Derived : PolymorphicTypeWithIgnoredConflictingPropertyName; + } + + [Fact] + public async Task PolymorphicTypeWithExtensionDataConflictingPropertyName_Supported() + { + PolymorphicTypeWithExtensionDataConflictingPropertyName value = new PolymorphicTypeWithExtensionDataConflictingPropertyName.Derived(); + + JsonTypeInfo typeInfo = Serializer.GetTypeInfo(typeof(PolymorphicTypeWithIgnoredConflictingPropertyName)); + Assert.NotNull(typeInfo); + + string json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"Type":"Derived"}""", json); + + value = await Serializer.DeserializeWrapper("""{"Type":"Derived","extraProp":null}"""); + Assert.IsType(value); + Assert.Equal(1, value.Type.Count); + Assert.Contains("extraProp", value.Type); + } + + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonDerivedType(typeof(Derived), nameof(Derived))] + public abstract class PolymorphicTypeWithExtensionDataConflictingPropertyName + { + [JsonExtensionData] + public JsonObject Type { get; set; } + + public class Derived : PolymorphicTypeWithExtensionDataConflictingPropertyName; + } } } From a3365e4c442a728bc82e59d5583cf83bc6d31d72 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:30:59 +0000 Subject: [PATCH 03/16] Clarify XML comments for Utf8Parser.TryParse to reflect case insensitivity (#103861) * Clarify XML comments for Utf8Parser.TryParse to reflect case insensitivity * Clarify doc * Update doc * Update src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs Co-authored-by: Tanner Gooding * Update src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs --------- Co-authored-by: joegoldman2 <147369450+joegoldman@users.noreply.github.com> Co-authored-by: Tanner Gooding --- .../System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs index b19cee4e43ecc..da378c06b7d70 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs @@ -12,16 +12,14 @@ public static partial class Utf8Parser /// /// The Utf8 string to parse /// Receives the parsed value - /// On a successful parse, receives the length in bytes of the substring that was parsed - /// Expected format of the Utf8 string + /// On a successful parse, receives the length in bytes of the substring that was parsed. + /// Expected format of the Utf8 string. Supported formats are 'G', 'l', and default. /// /// true for success. "bytesConsumed" contains the length in bytes of the substring that was parsed. /// false if the string was not syntactically valid or an overflow or underflow occurred. "bytesConsumed" is set to 0. /// /// - /// Formats supported: - /// G (default) True/False - /// l true/false + /// The parsing is case insensitive. The format parameter is validated to ensure it is supported; however, all supported formats are treated identically. /// /// /// System.FormatException if the format is not valid for this data type. From c4cc79468afffe455a827080c9ef88f34a1976fe Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed <10833894+tarekgh@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:30:37 -0700 Subject: [PATCH 04/16] Fix config source gen binding with SslClientAuthenticationOptions (#107579) * Fix config source gen binding with SslClientAuthenticationOptions * Apply suggestions from code review Co-authored-by: Eric Erhardt --------- Co-authored-by: Eric Erhardt --- .../gen/Emitter/CoreBindingHelpers.cs | 9 +++++ .../SourceGenerationTests/GeneratorTests.cs | 33 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs index fabdebd67eb4b..685850bb16e2a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs @@ -901,6 +901,15 @@ private bool EmitBindImplForMember( } case ComplexTypeSpec complexType: { + // Early detection of types we cannot bind to and skip it. + if (!_typeIndex.HasBindableMembers(complexType) && + !_typeIndex.GetEffectiveTypeSpec(complexType).IsValueType && + complexType is not CollectionSpec && + ((ObjectSpec)complexType).InstantiationStrategy == ObjectInstantiationStrategy.ParameterizedConstructor) + { + return false; + } + string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})"; string sectionIdentifier = GetIncrementalIdentifier(Identifier.section); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index f4f9c906a9354..1442c623f3fa0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -257,6 +257,39 @@ async Task Test(bool expectOutput) } } + /// + /// We binding the type "SslClientAuthenticationOptions" which has a property "CipherSuitesPolicy" of type "CipherSuitesPolicy". We can't bind this type. + /// This test is to ensure not including the property "CipherSuitesPolicy" in the generated code caused a build break. + /// + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task IgnoredUnBindablePropertiesTest() + { + string source = """ + using System; + using System.Net.Security; + using Microsoft.Extensions.Configuration; + using System.Collections.Immutable; + using System.Text; + using System.Text.Json; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration config = configurationBuilder.Build(); + + var obj = config.Get(); + } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source, assemblyReferences: GetAssemblyRefsWithAdditional(typeof(ImmutableArray<>), typeof(Encoding), typeof(JsonSerializer), typeof(System.Net.Security.AuthenticatedStream))); + Assert.NotNull(result.GeneratedSource); + + Assert.DoesNotContain("CipherSuitesPolicy = ", result.GeneratedSource.Value.SourceText.ToString()); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] [ActiveIssue("Work out why we aren't getting all the expected diagnostics.")] public async Task IssueDiagnosticsForAllOffendingCallsites() From c381595dad2f3b898096513472dabfd5264b5042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Hompus?= Date: Wed, 11 Sep 2024 22:18:28 +0200 Subject: [PATCH 05/16] Provide System.CodeDom package readme (#107372) * Provide System.CodeDom package readme * Add remark about Roslyn/.NET Compiler SDK * Update src/libraries/System.CodeDom/src/PACKAGE.md --------- Co-authored-by: Buyaa Namnan --- src/libraries/System.CodeDom/src/PACKAGE.md | 127 ++++++++++++++++++ .../System.CodeDom/src/System.CodeDom.csproj | 10 +- 2 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 src/libraries/System.CodeDom/src/PACKAGE.md diff --git a/src/libraries/System.CodeDom/src/PACKAGE.md b/src/libraries/System.CodeDom/src/PACKAGE.md new file mode 100644 index 0000000000000..2785a3e5888a3 --- /dev/null +++ b/src/libraries/System.CodeDom/src/PACKAGE.md @@ -0,0 +1,127 @@ +## About + + + +Provides functionality for dynamically generating and compiling source code using the Code Document Object Model (CodeDOM). + +It allows developers to represent code in a language-agnostic format and then generate code in multiple languages, such as C# and VB.NET. +The primary use cases include creating dynamic code generation tools, runtime code generation, and facilitating code analysis or transformation. + +For a new modern development consider using the [.NET Compiler Platform SDK](https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/), in particular [Roslyn source generators](https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/source-generators-overview#get-started-with-source-generators). + +## Key Features + + + +* Write code using a common object model that can be translated into multiple programming languages. +* Generate and compile code at runtime based on the CodeDOM. + +## How to Use + + + +Generating and compiling C# code: + +```csharp +using System.CodeDom; +using System.CodeDom.Compiler; +using Microsoft.CSharp; + +// Create a new CodeCompileUnit to hold the code +var compileUnit = new CodeCompileUnit(); + +// Create a namespace +var codeNamespace = new CodeNamespace("MyNamespace"); +compileUnit.Namespaces.Add(codeNamespace); + +// Create a class +var classDeclaration = new CodeTypeDeclaration("MyClass") +{ + IsClass = true +}; +codeNamespace.Types.Add(classDeclaration); + +// Add a simple method to the class +var method = new CodeMemberMethod +{ + Name = "HelloWorld", + ReturnType = new CodeTypeReference(typeof(void)), +}; +classDeclaration.Members.Add(method); + +var methodInvocation = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("Console"), + "WriteLine", + new CodePrimitiveExpression("Hello, World!")); +method.Statements.Add(methodInvocation); + +// Generate C# code from the CodeDOM structure +CodeDomProvider provider = new CSharpCodeProvider(); + +using (var writer = new StringWriter()) +{ + var codeGenereationOptions = new CodeGeneratorOptions() + { + BlankLinesBetweenMembers = false, + IndentString = " ", + }; + + provider.GenerateCodeFromCompileUnit(compileUnit, writer, codeGenereationOptions); + Console.WriteLine(writer.GetStringBuilder().ToString()); +} +``` + +This example generates: + +```csharp +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MyNamespace { + + public class MyClass { + private void HelloWorld() { + Console.WriteLine("Hello, World!"); + } + } +} +``` + +## Main Types + + + +The main types provided by this library are: + +* `System.CodeDom.CodeObject` +* `System.CodeDom.CodeCompileUnit` +* `System.CodeDom.CodeNamespace` +* `System.CodeDom.CodeTypeDeclaration` +* `System.CodeDom.CodeMemberMethod` +* `System.CodeDom.CodeTypeReference` +* `System.CodeDom.CodeMethodInvokeExpression` +* `System.CodeDom.CodeTypeReferenceExpression` +* `System.CodeDom.CodePrimitiveExpression` +* `System.CodeDom.Compiler.CodeDomProvider` +* `System.CodeDom.Compiler.CodeGeneratorOptions` +* `Microsoft.CSharp.CSharpCodeProvider` +* `Microsoft.VisualBasic.VBCodeProvider` + +## Additional Documentation + + + +* [API documentation](https://learn.microsoft.com/dotnet/api/system.codedom) +* [Compile and generate dynamic source code](https://learn.microsoft.com/dotnet/framework/reflection-and-codedom/dynamic-source-code-generation-and-compilation) + +## Feedback & Contributing + + + +System.CodeDom is released as open source under the [MIT license](https://licenses.nuget.org/MIT). +Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.CodeDom/src/System.CodeDom.csproj b/src/libraries/System.CodeDom/src/System.CodeDom.csproj index a987278ff0539..76ba0e1a9d3f6 100644 --- a/src/libraries/System.CodeDom/src/System.CodeDom.csproj +++ b/src/libraries/System.CodeDom/src/System.CodeDom.csproj @@ -6,19 +6,11 @@ false false true - Provides types that can be used to model the structure of a source code document and to output source code for that model in a supported language. - -Commonly Used Types: -System.CodeDom.CodeObject -System.CodeDom.Compiler.CodeDomProvider -Microsoft.CSharp.CSharpCodeProvider -Microsoft.VisualBasic.VBCodeProvider + Provides types that can be used to model the structure of a source code document and to output source code for that model in C# or Visual Basic. disable $(NoWarn);nullable - - false From 3979ef8b848c0de914a6ac61745561f93fdf4209 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 11 Sep 2024 13:36:37 -0700 Subject: [PATCH 06/16] Use system brotli on Unix non-portable builds (#107225) Co-authored-by: Jan Kotas --- eng/DotNetBuild.props | 2 +- .../BuildIntegration/Microsoft.NETCore.Native.Unix.targets | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props index 3569781b9af49..ce13d6ca5b002 100644 --- a/eng/DotNetBuild.props +++ b/eng/DotNetBuild.props @@ -88,7 +88,7 @@ +$(UseSystemLibs)+ - $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_BROTLI=true + $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_BROTLI=true $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=true diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index d2696ffbcad6d..7338d13362184 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -168,6 +168,11 @@ The .NET Foundation licenses this file to you under the MIT license. + + + + + From 1231a9addd0fb3cfb806c2a89cb45a3018c48bb2 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 11 Sep 2024 16:49:12 -0400 Subject: [PATCH 07/16] =?UTF-8?q?Revert=20"Avoid=20taking=20lock=20for=20e?= =?UTF-8?q?mpty=20bucket=20in=20ConcurrentDictionary.TryRemove=20=E2=80=A6?= =?UTF-8?q?"=20(#107653)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 252018c3d3fffdb592413cf61d5b80cf751e0a59. --- .../Concurrent/ConcurrentDictionary.cs | 73 +++++++++---------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs index 3e05e5769dbf1..91387fbcde0b4 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -443,57 +443,52 @@ private bool TryRemoveInternal(TKey key, [MaybeNullWhen(false)] out TValue value object[] locks = tables._locks; ref Node? bucket = ref GetBucketAndLock(tables, hashcode, out uint lockNo); - // Do a hot read on number of items stored in the bucket. If it's empty, we can avoid - // taking the lock and fail fast. - if (tables._countPerLock[lockNo] != 0) + lock (locks[lockNo]) { - lock (locks[lockNo]) + // If the table just got resized, we may not be holding the right lock, and must retry. + // This should be a rare occurrence. + if (tables != _tables) { - // If the table just got resized, we may not be holding the right lock, and must retry. - // This should be a rare occurrence. - if (tables != _tables) + tables = _tables; + if (!ReferenceEquals(comparer, tables._comparer)) { - tables = _tables; - if (!ReferenceEquals(comparer, tables._comparer)) - { - comparer = tables._comparer; - hashcode = GetHashCode(comparer, key); - } - continue; + comparer = tables._comparer; + hashcode = GetHashCode(comparer, key); } + continue; + } - Node? prev = null; - for (Node? curr = bucket; curr is not null; curr = curr._next) - { - Debug.Assert((prev is null && curr == bucket) || prev!._next == curr); + Node? prev = null; + for (Node? curr = bucket; curr is not null; curr = curr._next) + { + Debug.Assert((prev is null && curr == bucket) || prev!._next == curr); - if (hashcode == curr._hashcode && NodeEqualsKey(comparer, curr, key)) + if (hashcode == curr._hashcode && NodeEqualsKey(comparer, curr, key)) + { + if (matchValue) { - if (matchValue) - { - bool valuesMatch = EqualityComparer.Default.Equals(oldValue, curr._value); - if (!valuesMatch) - { - value = default; - return false; - } - } - - if (prev is null) - { - Volatile.Write(ref bucket, curr._next); - } - else + bool valuesMatch = EqualityComparer.Default.Equals(oldValue, curr._value); + if (!valuesMatch) { - prev._next = curr._next; + value = default; + return false; } + } - value = curr._value; - tables._countPerLock[lockNo]--; - return true; + if (prev is null) + { + Volatile.Write(ref bucket, curr._next); } - prev = curr; + else + { + prev._next = curr._next; + } + + value = curr._value; + tables._countPerLock[lockNo]--; + return true; } + prev = curr; } } From 8e8e7f7851dcac7f58d248cbdc22e9dcb7e15a69 Mon Sep 17 00:00:00 2001 From: SwapnilGaikwad Date: Wed, 11 Sep 2024 23:23:15 +0100 Subject: [PATCH 08/16] Fix SVE ExtendWidening ConditionalSelect tests (#107601) * Fix SVE ExtendWidening ConditionalSelect tests Fixes: #107537 * Incorporate review comments --- .../GenerateHWIntrinsicTests_Arm.cs | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index c8bf71ecc4be4..ce96b7fc025aa 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -222,7 +222,7 @@ const string VecReduceUnOpTest_VectorValidationLogicForCndSel = @" { - var hasFailed = (mask[0] != 0 ? {ValidateReduceOpResult}: (falseVal[0] != result[0])); + var hasFailed = (mask[0] != 0) ? ({ValidateReduceOpResult}): (falseVal[0] != result[0]); if (hasFailed) { @@ -232,20 +232,11 @@ { for (var i = 1; i < RetElementCount; i++) { - var iterResult = (mask[i] != 0) ? 0 : falseVal[i]; - if (mask[i] != 0) + hasFailed = (mask[i] != 0) ? ({ValidateRemainingResults}) : (falseVal[i] != result[i]); + if (hasFailed) { - // Pick the trueValue - if (iterResult != result[i]) - { - succeeded = false; - break; - } - } - else - { - // For false, the values are merged with destination, and we do not know - // those contents would be, so skip verification for them. + succeeded = false; + break; } } } @@ -253,7 +244,7 @@ const string VecReduceUnOpTest_VectorValidationLogicForCndSel_FalseValue = @" { - var hasFailed = (mask[0] != 0) ? (trueVal[0] != result[0]): {ValidateReduceOpResult}; + var hasFailed = (mask[0] != 0) ? (trueVal[0] != result[0]): ({ValidateReduceOpResult}); if (hasFailed) { succeeded = false; @@ -262,20 +253,11 @@ { for (var i = 1; i < RetElementCount; i++) { - var iterResult = (mask[i] != 0) ? trueVal[i] : 0; - if (mask[i] != 0) + hasFailed = (mask[i] != 0) ? (trueVal[i] != result[i]) : ({ValidateRemainingResults}); + if (hasFailed) { - // Pick the trueValue - if (iterResult != result[i]) - { - succeeded = false; - break; - } - } - else - { - // For false, the values are merged with destination, and we do not know - // those contents would be, so skip verification for them. + succeeded = false; + break; } } } From 171f1a73a9f0fa77464995bcb893a59b9b98bc3d Mon Sep 17 00:00:00 2001 From: Omair Majid Date: Wed, 11 Sep 2024 19:43:00 -0400 Subject: [PATCH 09/16] Remove unused freebsd elf32/elf64 header references (#107657) These headers define the ELF structures, but the mono DWARF writer doesn't actually use them for anything. The headers may conflict when system libunwind is used. --- src/mono/mono/mini/dwarfwriter.c | 5 ----- src/mono/mono/utils/CMakeLists.txt | 6 ------ 2 files changed, 11 deletions(-) diff --git a/src/mono/mono/mini/dwarfwriter.c b/src/mono/mono/mini/dwarfwriter.c index 31ca33e9fd82c..aea4758c668e7 100644 --- a/src/mono/mono/mini/dwarfwriter.c +++ b/src/mono/mono/mini/dwarfwriter.c @@ -25,11 +25,6 @@ #include #include -#ifndef HOST_WIN32 -#include -#include -#endif - #include #define DW_AT_MIPS_linkage_name 0x2007 diff --git a/src/mono/mono/utils/CMakeLists.txt b/src/mono/mono/utils/CMakeLists.txt index ef271dcb830a9..8f5a70cfd3ff9 100644 --- a/src/mono/mono/utils/CMakeLists.txt +++ b/src/mono/mono/utils/CMakeLists.txt @@ -217,12 +217,6 @@ endif() set(utils_sources "${utils_platform_sources};${utils_arch_sources};${utils_common_sources}") -set(utils_sources - ${utils_sources} - ${CLR_SRC_NATIVE_DIR}/external/libunwind/include/remote/freebsd-elf_common.h - ${CLR_SRC_NATIVE_DIR}/external/libunwind/include/remote/freebsd-elf32.h - ${CLR_SRC_NATIVE_DIR}/external/libunwind/include/remote/freebsd-elf64.h) - if(ENABLE_DTRACE) find_program(DTRACE dtrace) if(TARGET_OSX) From 4930e1b44027484e13a29c7f3230e1f0bb397e7c Mon Sep 17 00:00:00 2001 From: Sanjam Panda <36253777+saitama951@users.noreply.github.com> Date: Thu, 12 Sep 2024 05:14:39 +0530 Subject: [PATCH 10/16] fix slag instruction (#107559) Fixes #107387 The slag instructions throws an undefined behavior when moving from Float to Int in OP_MOVE_I4_TO_F --- src/mono/mono/mini/mini-s390x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index e90a0e6770e15..3419a29768c70 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -3471,7 +3471,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_srag (code, ins->dreg, ins->dreg, 0, 32); break; case OP_MOVE_I4_TO_F: - s390_slag (code, s390_r0, ins->sreg1, 0, 32); + s390_sllg (code, s390_r0, ins->sreg1, 0, 32); s390_ldgr (code, ins->dreg, s390_r0); break; case OP_FCONV_TO_R4: From 4cdbfdcca352e0f12e4829eb3fec638d717add51 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Thu, 12 Sep 2024 11:09:15 +0200 Subject: [PATCH 11/16] [NRBF] More bug fixes (#107682) - Don't use `Debug.Fail` not followed by an exception (it may cause problems for apps deployed in Debug) - avoid Int32 overflow - throw for unexpected enum values just in case parsing has not rejected them - validate the number of chars read by BinaryReader.ReadChars - pass serialization record id to ex message - return false rather than throw EndOfStreamException when provided Stream has not enough data - don't restore the position in finally - limit max SZ and MD array length to Array.MaxLength, stop using LinkedList as List will be able to hold all elements now - remove internal enum values that were always illegal, but needed to be handled everywhere - Fix DebuggerDisplay --- .../src/System/Formats/Nrbf/ArrayInfo.cs | 2 +- .../Nrbf/ArraySinglePrimitiveRecord.cs | 43 ++++--------------- .../Formats/Nrbf/ArraySingleStringRecord.cs | 2 +- .../System/Formats/Nrbf/BinaryArrayRecord.cs | 2 +- .../Formats/Nrbf/BinaryLibraryRecord.cs | 9 +--- .../src/System/Formats/Nrbf/MemberTypeInfo.cs | 19 +++++--- .../System/Formats/Nrbf/MessageEndRecord.cs | 9 +--- .../src/System/Formats/Nrbf/NrbfDecoder.cs | 40 ++++++++--------- .../src/System/Formats/Nrbf/NullsRecord.cs | 9 +--- .../src/System/Formats/Nrbf/PrimitiveType.cs | 22 +++++++--- .../src/System/Formats/Nrbf/RecordMap.cs | 2 +- .../Formats/Nrbf/RectangularArrayRecord.cs | 30 ++++++------- .../Formats/Nrbf/SerializationRecord.cs | 4 +- .../Formats/Nrbf/SerializationRecordId.cs | 2 + .../Nrbf/SerializedStreamHeaderRecord.cs | 10 +---- .../Nrbf/Utils/BinaryReaderExtensions.cs | 17 ++++++-- .../Formats/Nrbf/Utils/TypeNameHelpers.cs | 11 +++-- 17 files changed, 97 insertions(+), 136 deletions(-) diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs index e8b28825888e4..4b24b1912e89a 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs @@ -13,7 +13,7 @@ namespace System.Formats.Nrbf; /// /// ArrayInfo structures are described in [MS-NRBF] 2.4.2.1. /// -[DebuggerDisplay("Length={Length}, {ArrayType}, rank={Rank}")] +[DebuggerDisplay("{ArrayType}, rank={Rank}")] internal readonly struct ArrayInfo { internal const int MaxArrayLength = 2147483591; // Array.MaxLength diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs index 5b3b974639468..46693c344bc84 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs @@ -41,17 +41,9 @@ internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList values public override T[] GetArray(bool allowNulls = true) => (T[])(_arrayNullsNotAllowed ??= (Values is T[] array ? array : Values.ToArray())); - internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType() - { - Debug.Fail("GetAllowedRecordType should never be called on ArraySinglePrimitiveRecord"); - throw new InvalidOperationException(); - } + internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType() => throw new InvalidOperationException(); - private protected override void AddValue(object value) - { - Debug.Fail("AddValue should never be called on ArraySinglePrimitiveRecord"); - throw new InvalidOperationException(); - } + private protected override void AddValue(object value) => throw new InvalidOperationException(); internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int count) { @@ -94,7 +86,7 @@ internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int c #if NET reader.BaseStream.ReadExactly(resultAsBytes); #else - byte[] bytes = ArrayPool.Shared.Rent(Math.Min(count * Unsafe.SizeOf(), 256_000)); + byte[] bytes = ArrayPool.Shared.Rent((int)Math.Min(requiredBytes, 256_000)); while (!resultAsBytes.IsEmpty) { @@ -159,31 +151,10 @@ internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int c private static List DecodeDecimals(BinaryReader reader, int count) { List values = new(); -#if NET - Span buffer = stackalloc byte[256]; - for (int i = 0; i < count; i++) - { - int stringLength = reader.Read7BitEncodedInt(); - if (!(stringLength > 0 && stringLength <= buffer.Length)) - { - ThrowHelper.ThrowInvalidValue(stringLength); - } - - reader.BaseStream.ReadExactly(buffer.Slice(0, stringLength)); - - if (!decimal.TryParse(buffer.Slice(0, stringLength), NumberStyles.Number, CultureInfo.InvariantCulture, out decimal value)) - { - ThrowHelper.ThrowInvalidFormat(); - } - - values.Add(value); - } -#else for (int i = 0; i < count; i++) { values.Add(reader.ParseDecimal()); } -#endif return values; } @@ -244,12 +215,14 @@ private static List DecodeFromNonSeekableStream(BinaryReader reader, int coun { values.Add((T)(object)Utils.BinaryReaderExtensions.CreateDateTimeFromData(reader.ReadUInt64())); } - else + else if (typeof(T) == typeof(TimeSpan)) { - Debug.Assert(typeof(T) == typeof(TimeSpan)); - values.Add((T)(object)new TimeSpan(reader.ReadInt64())); } + else + { + throw new InvalidOperationException(); + } } return values; diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs index de248bcef7675..7fed2a494b9b0 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs @@ -21,7 +21,7 @@ internal sealed class ArraySingleStringRecord : SZArrayRecord public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleString; /// - public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String); + public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.StringPrimitiveType); private List Records { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs index 0c7e04e840a48..5aa4878016d9f 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs @@ -138,7 +138,7 @@ internal static ArrayRecord Decode(BinaryReader reader, RecordMap recordMap, Pay lengths[i] = ArrayInfo.ParseValidArrayLength(reader); totalElementCount *= lengths[i]; - if (totalElementCount > uint.MaxValue) + if (totalElementCount > ArrayInfo.MaxArrayLength) { ThrowHelper.ThrowInvalidValue(lengths[i]); // max array size exceeded } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs index ccd39922e23fb..7318052610e1b 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs @@ -30,14 +30,7 @@ private BinaryLibraryRecord(SerializationRecordId libraryId, AssemblyNameInfo li public override SerializationRecordType RecordType => SerializationRecordType.BinaryLibrary; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on BinaryLibraryRecord"); - return TypeName.Parse(nameof(BinaryLibraryRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(BinaryLibraryRecord).AsSpan()); internal string? RawLibraryName { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs index 9843a0b71f04c..2e4b7e1399be2 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs @@ -53,10 +53,14 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt case BinaryType.Class: info[i] = (type, ClassTypeInfo.Decode(reader, options, recordMap)); break; - default: - // Other types have no additional data. - Debug.Assert(type is BinaryType.String or BinaryType.ObjectArray or BinaryType.StringArray or BinaryType.Object); + case BinaryType.String: + case BinaryType.StringArray: + case BinaryType.Object: + case BinaryType.ObjectArray: + // These types have no additional data. break; + default: + throw new InvalidOperationException(); } } @@ -97,7 +101,8 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt BinaryType.PrimitiveArray => (PrimitiveArray, default), BinaryType.Class => (NonSystemClass, default), BinaryType.SystemClass => (SystemClass, default), - _ => (ObjectArray, default) + BinaryType.ObjectArray => (ObjectArray, default), + _ => throw new InvalidOperationException() }; } @@ -144,15 +149,15 @@ internal TypeName GetArrayTypeName(ArrayInfo arrayInfo) TypeName elementTypeName = binaryType switch { - BinaryType.String => TypeNameHelpers.GetPrimitiveTypeName(PrimitiveType.String), - BinaryType.StringArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String), + BinaryType.String => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.StringPrimitiveType), + BinaryType.StringArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.StringPrimitiveType), BinaryType.Primitive => TypeNameHelpers.GetPrimitiveTypeName((PrimitiveType)additionalInfo!), BinaryType.PrimitiveArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName((PrimitiveType)additionalInfo!), BinaryType.Object => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.ObjectPrimitiveType), BinaryType.ObjectArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.ObjectPrimitiveType), BinaryType.SystemClass => (TypeName)additionalInfo!, BinaryType.Class => ((ClassTypeInfo)additionalInfo!).TypeName, - _ => throw new ArgumentOutOfRangeException(paramName: nameof(binaryType), actualValue: binaryType, message: null) + _ => throw new InvalidOperationException() }; // In general, arrayRank == 1 may have two different meanings: diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs index 7cb28224a890e..62c7d57b3fa37 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs @@ -24,12 +24,5 @@ private MessageEndRecord() public override SerializationRecordId Id => SerializationRecordId.NoId; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on MessageEndRecord"); - return TypeName.Parse(nameof(MessageEndRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(MessageEndRecord).AsSpan()); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs index de4b24b6e46e1..fc03409bd2eec 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs @@ -69,28 +69,22 @@ public static bool StartsWithPayloadHeader(Stream stream) return false; } - try + byte[] buffer = new byte[SerializedStreamHeaderRecord.Size]; + int offset = 0; + while (offset < buffer.Length) { -#if NET - Span buffer = stackalloc byte[SerializedStreamHeaderRecord.Size]; - stream.ReadExactly(buffer); -#else - byte[] buffer = new byte[SerializedStreamHeaderRecord.Size]; - int offset = 0; - while (offset < buffer.Length) + int read = stream.Read(buffer, offset, buffer.Length - offset); + if (read == 0) { - int read = stream.Read(buffer, offset, buffer.Length - offset); - if (read == 0) - throw new EndOfStreamException(); - offset += read; + stream.Position = beginning; + return false; } -#endif - return StartsWithPayloadHeader(buffer); - } - finally - { - stream.Position = beginning; + offset += read; } + + bool result = StartsWithPayloadHeader(buffer); + stream.Position = beginning; + return result; } /// @@ -241,7 +235,8 @@ private static SerializationRecord DecodeNext(BinaryReader reader, RecordMap rec SerializationRecordType.ObjectNullMultiple => ObjectNullMultipleRecord.Decode(reader), SerializationRecordType.ObjectNullMultiple256 => ObjectNullMultiple256Record.Decode(reader), SerializationRecordType.SerializedStreamHeader => SerializedStreamHeaderRecord.Decode(reader), - _ => SystemClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), + SerializationRecordType.SystemClassWithMembersAndTypes => SystemClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), + _ => throw new InvalidOperationException() }; recordMap.Add(record); @@ -269,8 +264,8 @@ private static SerializationRecord DecodeMemberPrimitiveTypedRecord(BinaryReader PrimitiveType.Double => new MemberPrimitiveTypedRecord(reader.ReadDouble()), PrimitiveType.Decimal => new MemberPrimitiveTypedRecord(reader.ParseDecimal()), PrimitiveType.DateTime => new MemberPrimitiveTypedRecord(Utils.BinaryReaderExtensions.CreateDateTimeFromData(reader.ReadUInt64())), - // String is handled with a record, never on it's own - _ => new MemberPrimitiveTypedRecord(new TimeSpan(reader.ReadInt64())), + PrimitiveType.TimeSpan => new MemberPrimitiveTypedRecord(new TimeSpan(reader.ReadInt64())), + _ => throw new InvalidOperationException() }; } @@ -295,7 +290,8 @@ private static SerializationRecord DecodeArraySinglePrimitiveRecord(BinaryReader PrimitiveType.Double => Decode(info, reader), PrimitiveType.Decimal => Decode(info, reader), PrimitiveType.DateTime => Decode(info, reader), - _ => Decode(info, reader), + PrimitiveType.TimeSpan => Decode(info, reader), + _ => throw new InvalidOperationException() }; static SerializationRecord Decode(ArrayInfo info, BinaryReader reader) where T : unmanaged diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs index d3d859c193a9c..9c11db4307ced 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs @@ -12,12 +12,5 @@ internal abstract class NullsRecord : SerializationRecord public override SerializationRecordId Id => SerializationRecordId.NoId; - public override TypeName TypeName - { - get - { - Debug.Fail($"TypeName should never be called on {GetType().Name}"); - return TypeName.Parse(GetType().Name.AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(GetType().Name.AsSpan()); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs index 9ddb9179518fa..f2e696e6a90e9 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs @@ -11,10 +11,6 @@ namespace System.Formats.Nrbf; /// internal enum PrimitiveType : byte { - /// - /// Used internally to express no value - /// - None = 0, Boolean = 1, Byte = 2, Char = 3, @@ -30,7 +26,19 @@ internal enum PrimitiveType : byte DateTime = 13, UInt16 = 14, UInt32 = 15, - UInt64 = 16, - Null = 17, - String = 18 + UInt64 = 16 + // This internal enum no longer contains Null and String as they were always illegal: + // - In case of BinaryArray (NRBF 2.4.3.1): + // "If the BinaryTypeEnum value is Primitive, the PrimitiveTypeEnumeration + // value in AdditionalTypeInfo MUST NOT be Null (17) or String (18)." + // - In case of MemberPrimitiveTyped (NRBF 2.5.1): + // "PrimitiveTypeEnum (1 byte): A PrimitiveTypeEnumeration + // value that specifies the Primitive Type of data that is being transmitted. + // This field MUST NOT contain a value of 17 (Null) or 18 (String)." + // - In case of ArraySinglePrimitive (NRBF 2.4.3.3): + // "A PrimitiveTypeEnumeration value that identifies the Primitive Type + // of the items of the Array. The value MUST NOT be 17 (Null) or 18 (String)." + // - In case of MemberTypeInfo (NRBF 2.3.1.2): + // "When the BinaryTypeEnum value is Primitive, the PrimitiveTypeEnumeration + // value in AdditionalInfo MUST NOT be Null (17) or String (18)." } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs index 04a4d0e085048..eafcbf93249c5 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs @@ -56,7 +56,7 @@ internal void Add(SerializationRecord record) return; } #endif - throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.Id)); + throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.Id._id)); } } } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs index de3c6d671850a..bc286e56ee5c2 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs @@ -14,7 +14,7 @@ namespace System.Formats.Nrbf; internal sealed class RectangularArrayRecord : ArrayRecord { private readonly int[] _lengths; - private readonly ICollection _values; + private readonly List _values; private TypeName? _typeName; private RectangularArrayRecord(Type elementType, ArrayInfo arrayInfo, @@ -24,18 +24,8 @@ private RectangularArrayRecord(Type elementType, ArrayInfo arrayInfo, MemberTypeInfo = memberTypeInfo; _lengths = lengths; - // A List can hold as many objects as an array, so for multi-dimensional arrays - // with more elements than Array.MaxLength we use LinkedList. - // Testing that many elements takes a LOT of time, so to ensure that both code paths are tested, - // we always use LinkedList code path for Debug builds. -#if DEBUG - _values = new LinkedList(); -#else - _values = arrayInfo.TotalElementsCount <= ArrayInfo.MaxArrayLength - ? new List(canPreAllocate ? arrayInfo.GetSZArrayLength() : Math.Min(4, arrayInfo.GetSZArrayLength())) - : new LinkedList(); -#endif - + // ArrayInfo.GetSZArrayLength ensures to return a value <= Array.MaxLength + _values = new List(canPreAllocate ? arrayInfo.GetSZArrayLength() : Math.Min(4, arrayInfo.GetSZArrayLength())); } public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray; @@ -108,6 +98,7 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) else if (ElementType == typeof(TimeSpan)) CopyTo(_values, result); else if (ElementType == typeof(DateTime)) CopyTo(_values, result); else if (ElementType == typeof(decimal)) CopyTo(_values, result); + else throw new InvalidOperationException(); } else { @@ -116,7 +107,7 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) return result; - static void CopyTo(ICollection list, Array array) + static void CopyTo(List list, Array array) { ref byte arrayDataRef = ref MemoryMarshal.GetArrayDataReference(array); ref T firstElementRef = ref Unsafe.As(ref arrayDataRef); @@ -176,7 +167,10 @@ internal static RectangularArrayRecord Create(BinaryReader reader, ArrayInfo arr PrimitiveType.Int64 => sizeof(long), PrimitiveType.UInt64 => sizeof(ulong), PrimitiveType.Double => sizeof(double), - _ => -1 + PrimitiveType.TimeSpan => sizeof(ulong), + PrimitiveType.DateTime => sizeof(ulong), + PrimitiveType.Decimal => -1, // represented as variable-length string + _ => throw new InvalidOperationException() }; if (sizeOfSingleValue > 0) @@ -215,7 +209,8 @@ private static Type MapPrimitive(PrimitiveType primitiveType) PrimitiveType.DateTime => typeof(DateTime), PrimitiveType.UInt16 => typeof(ushort), PrimitiveType.UInt32 => typeof(uint), - _ => typeof(ulong) + PrimitiveType.UInt64 => typeof(ulong), + _ => throw new InvalidOperationException() }; private static Type MapPrimitiveArray(PrimitiveType primitiveType) @@ -235,7 +230,8 @@ private static Type MapPrimitiveArray(PrimitiveType primitiveType) PrimitiveType.DateTime => typeof(DateTime[]), PrimitiveType.UInt16 => typeof(ushort[]), PrimitiveType.UInt32 => typeof(uint[]), - _ => typeof(ulong[]), + PrimitiveType.UInt64 => typeof(ulong[]), + _ => throw new InvalidOperationException() }; private static object? GetActualValue(object value) diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs index 531ff87cd894e..09af5ff0a4ed3 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs @@ -114,8 +114,8 @@ private static bool Matches(Type type, TypeName typeName) internal virtual object? GetValue() => this; internal virtual void HandleNextRecord(SerializationRecord nextRecord, NextInfo info) - => Debug.Fail($"HandleNextRecord should not have been called for '{GetType().Name}'"); + => throw new InvalidOperationException(); internal virtual void HandleNextValue(object value, NextInfo info) - => Debug.Fail($"HandleNextValue should not have been called for '{GetType().Name}'"); + => throw new InvalidOperationException(); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs index 7f51525e6e113..a7478f5e3ffe0 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Formats.Nrbf.Utils; using System.IO; using System.Linq; @@ -15,6 +16,7 @@ namespace System.Formats.Nrbf; /// /// The ID of . /// +[DebuggerDisplay("{_id}")] public readonly struct SerializationRecordId : IEquatable { #pragma warning disable CS0649 // the default value is used on purpose diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs index 4757958fcb777..b21ff8ca23732 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs @@ -24,14 +24,8 @@ internal sealed class SerializedStreamHeaderRecord : SerializationRecord public override SerializationRecordType RecordType => SerializationRecordType.SerializedStreamHeader; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on SerializedStreamHeaderRecord"); - return TypeName.Parse(nameof(SerializedStreamHeaderRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(SerializedStreamHeaderRecord).AsSpan()); + public override SerializationRecordId Id => SerializationRecordId.NoId; internal SerializationRecordId RootId { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs index ff422c29401a1..a174d11dfffbe 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs @@ -60,8 +60,8 @@ internal static BinaryType ReadBinaryType(this BinaryReader reader) internal static PrimitiveType ReadPrimitiveType(this BinaryReader reader) { byte primitiveType = reader.ReadByte(); - // String is the last defined value, 4 is not used at all. - if (primitiveType is 0 or 4 or (byte)PrimitiveType.Null or > (byte)PrimitiveType.String) + // Boolean is the first valid value (1), UInt64 (16) is the last one. 4 is not used at all. + if (primitiveType is 4 or < (byte)PrimitiveType.Boolean or > (byte)PrimitiveType.UInt64) { ThrowHelper.ThrowInvalidValue(primitiveType); } @@ -88,7 +88,8 @@ internal static object ReadPrimitiveValue(this BinaryReader reader, PrimitiveTyp PrimitiveType.Double => reader.ReadDouble(), PrimitiveType.Decimal => reader.ParseDecimal(), PrimitiveType.DateTime => CreateDateTimeFromData(reader.ReadUInt64()), - _ => new TimeSpan(reader.ReadInt64()), + PrimitiveType.TimeSpan => new TimeSpan(reader.ReadInt64()), + _ => throw new InvalidOperationException(), }; // BinaryFormatter serializes decimals as strings and we can't BinaryReader.ReadDecimal. @@ -117,14 +118,22 @@ internal static char ParseChar(this BinaryReader reader) internal static char[] ParseChars(this BinaryReader reader, int count) { + char[]? result; try { - return reader.ReadChars(count); + result = reader.ReadChars(count); } catch (ArgumentException) // A surrogate character was read. { throw new SerializationException(SR.Serialization_SurrogateCharacter); } + + if (result.Length != count) + { + ThrowHelper.ThrowEndOfStreamException(); + } + + return result; } /// diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs index 97c3b4e42f68b..1c08a5c24eca5 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs @@ -12,7 +12,8 @@ namespace System.Formats.Nrbf.Utils; internal static class TypeNameHelpers { - // PrimitiveType does not define Object, IntPtr or UIntPtr + // PrimitiveType does not define Object, IntPtr or UIntPtr. + internal const PrimitiveType StringPrimitiveType = (PrimitiveType)18; internal const PrimitiveType ObjectPrimitiveType = (PrimitiveType)19; internal const PrimitiveType IntPtrPrimitiveType = (PrimitiveType)20; internal const PrimitiveType UIntPtrPrimitiveType = (PrimitiveType)21; @@ -22,8 +23,6 @@ internal static class TypeNameHelpers internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType) { - Debug.Assert(primitiveType is not (PrimitiveType.None or PrimitiveType.Null)); - TypeName? typeName = s_primitiveTypeNames[(int)primitiveType]; if (typeName is null) { @@ -44,11 +43,11 @@ internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType) PrimitiveType.Decimal => "System.Decimal", PrimitiveType.TimeSpan => "System.TimeSpan", PrimitiveType.DateTime => "System.DateTime", - PrimitiveType.String => "System.String", + StringPrimitiveType => "System.String", ObjectPrimitiveType => "System.Object", IntPtrPrimitiveType => "System.IntPtr", UIntPtrPrimitiveType => "System.UIntPtr", - _ => throw new ArgumentOutOfRangeException(paramName: nameof(primitiveType), actualValue: primitiveType, message: null) + _ => throw new InvalidOperationException() }; s_primitiveTypeNames[(int)primitiveType] = typeName = TypeName.Parse(fullName.AsSpan()).WithCoreLibAssemblyName(); @@ -99,7 +98,7 @@ internal static PrimitiveType GetPrimitiveType() else if (typeof(T) == typeof(TimeSpan)) return PrimitiveType.TimeSpan; else if (typeof(T) == typeof(string)) - return PrimitiveType.String; + return StringPrimitiveType; else if (typeof(T) == typeof(IntPtr)) return IntPtrPrimitiveType; else if (typeof(T) == typeof(UIntPtr)) From 122eb75149baeeb902f39cafb6f88be45f19f691 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 08:49:26 -0500 Subject: [PATCH 12/16] [main] Update dependencies from dotnet/arcade (#107027) * Update dependencies from https://github.com/dotnet/arcade build 20240826.3 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24423.2 -> To Version 9.0.0-beta.24426.3 * Update dependencies from https://github.com/dotnet/arcade build 20240828.1 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24426.3 -> To Version 9.0.0-beta.24428.1 * Update dependencies from https://github.com/dotnet/arcade build 20240829.6 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24428.1 -> To Version 10.0.0-beta.24429.6 * Update dependencies from https://github.com/dotnet/arcade build 20240830.1 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24429.6 -> To Version 10.0.0-beta.24430.1 * Update dependencies from https://github.com/dotnet/arcade build 20240905.1 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24430.1 -> To Version 10.0.0-beta.24455.1 * Update dependencies from https://github.com/dotnet/arcade build 20240906.3 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24455.1 -> To Version 10.0.0-beta.24456.3 * Update dependencies from https://github.com/dotnet/arcade build 20240909.1 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24456.3 -> To Version 10.0.0-beta.24459.1 * Update dependencies from https://github.com/dotnet/arcade build 20240909.12 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24459.1 -> To Version 10.0.0-beta.24459.12 * Update dependencies from https://github.com/dotnet/arcade build 20240911.3 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 10.0.0-beta.24459.12 -> To Version 10.0.0-beta.24461.3 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 84 +++++++++---------- eng/Versions.props | 32 +++---- .../job/source-index-stage1.yml | 47 ++--------- .../core-templates/steps/publish-logs.yml | 1 + .../steps/source-index-stage1-publish.yml | 35 ++++++++ .../steps/source-index-stage1-publish.yml | 7 ++ .../steps/source-index-stage1-publish.yml | 7 ++ global.json | 6 +- 8 files changed, 116 insertions(+), 103 deletions(-) create mode 100644 eng/common/core-templates/steps/source-index-stage1-publish.yml create mode 100644 eng/common/templates-official/steps/source-index-stage1-publish.yml create mode 100644 eng/common/templates/steps/source-index-stage1-publish.yml diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 23531192c5aae..b24be66d02d79 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -88,87 +88,87 @@ - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 https://github.com/dotnet/runtime-assets @@ -328,9 +328,9 @@ https://github.com/dotnet/xharness df9b6509e6b3976d158e46c23d72d6acd9f0d326 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + a1d1655b4d03677263fe9d5b8ec5edcb7be49044 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 89e58c6fce549..6103f74a4c707 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -84,22 +84,22 @@ 10.0.100-alpha.2.24459.4 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 2.9.0-beta.24423.2 - 9.0.0-beta.24423.2 - 2.9.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 - 9.0.0-beta.24423.2 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 2.9.0-beta.24461.3 + 10.0.0-beta.24461.3 + 2.9.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 + 10.0.0-beta.24461.3 1.4.0 diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml index 205fb5b3a3956..30530359a5d6d 100644 --- a/eng/common/core-templates/job/source-index-stage1.yml +++ b/eng/common/core-templates/job/source-index-stage1.yml @@ -1,8 +1,5 @@ parameters: runAsPublic: false - sourceIndexUploadPackageVersion: 2.0.0-20240522.1 - sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1 - sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog @@ -16,12 +13,6 @@ jobs: dependsOn: ${{ parameters.dependsOn }} condition: ${{ parameters.condition }} variables: - - name: SourceIndexUploadPackageVersion - value: ${{ parameters.sourceIndexUploadPackageVersion }} - - name: SourceIndexProcessBinlogPackageVersion - value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }} - - name: SourceIndexPackageSource - value: ${{ parameters.sourceIndexPackageSource }} - name: BinlogPath value: ${{ parameters.binlogPath }} - template: /eng/common/core-templates/variables/pool-providers.yml @@ -34,12 +25,10 @@ jobs: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: $(DncEngPublicBuildPool) - image: 1es-windows-2022-open - os: windows + image: windows.vs2022.amd64.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 - os: windows + image: windows.vs2022.amd64 steps: - ${{ if eq(parameters.is1ESPipeline, '') }}: @@ -47,35 +36,9 @@ jobs: - ${{ each preStep in parameters.preSteps }}: - ${{ preStep }} - - - task: UseDotNet@2 - displayName: Use .NET 8 SDK - inputs: - packageType: sdk - version: 8.0.x - installationPath: $(Agent.TempDirectory)/dotnet - workingDirectory: $(Agent.TempDirectory) - - - script: | - $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - displayName: Download Tools - # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. - workingDirectory: $(Agent.TempDirectory) - - script: ${{ parameters.sourceIndexBuildCommand }} displayName: Build Repository - - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output - displayName: Process Binlog into indexable sln - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: AzureCLI@2 - displayName: Log in to Azure and upload stage1 artifacts to source index - inputs: - azureSubscription: 'SourceDotNet Stage1 Publish' - addSpnToEnvironment: true - scriptType: 'ps' - scriptLocation: 'inlineScript' - inlineScript: | - $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1 + - template: /eng/common/core-templates/steps/source-index-stage1-publish.yml + parameters: + binLogPath: ${{ parameters.binLogPath }} \ No newline at end of file diff --git a/eng/common/core-templates/steps/publish-logs.yml b/eng/common/core-templates/steps/publish-logs.yml index 80788c5231912..173bcfe5ceed8 100644 --- a/eng/common/core-templates/steps/publish-logs.yml +++ b/eng/common/core-templates/steps/publish-logs.yml @@ -45,6 +45,7 @@ steps: SourceFolder: '$(Build.SourcesDirectory)/PostBuildLogs' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)/PostBuildLogs' + condition: always() - template: /eng/common/core-templates/steps/publish-build-artifacts.yml parameters: diff --git a/eng/common/core-templates/steps/source-index-stage1-publish.yml b/eng/common/core-templates/steps/source-index-stage1-publish.yml new file mode 100644 index 0000000000000..473a22c4719dc --- /dev/null +++ b/eng/common/core-templates/steps/source-index-stage1-publish.yml @@ -0,0 +1,35 @@ +parameters: + sourceIndexUploadPackageVersion: 2.0.0-20240522.1 + sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1 + sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json + binlogPath: artifacts/log/Debug/Build.binlog + +steps: +- task: UseDotNet@2 + displayName: "Source Index: Use .NET 8 SDK" + inputs: + packageType: sdk + version: 8.0.x + installationPath: $(Agent.TempDirectory)/dotnet + workingDirectory: $(Agent.TempDirectory) + +- script: | + $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version ${{parameters.sourceIndexProcessBinlogPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools + $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version ${{parameters.sourceIndexUploadPackageVersion}} --add-source ${{parameters.SourceIndexPackageSource}} --tool-path $(Agent.TempDirectory)/.source-index/tools + displayName: "Source Index: Download netsourceindex Tools" + # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. + workingDirectory: $(Agent.TempDirectory) + +- script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i ${{parameters.BinlogPath}} -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output + displayName: "Source Index: Process Binlog into indexable sln" + +- ${{ if and(ne(parameters.runAsPublic, 'true'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - task: AzureCLI@2 + displayName: "Source Index: Upload Source Index stage1 artifacts to Azure" + inputs: + azureSubscription: 'SourceDotNet Stage1 Publish' + addSpnToEnvironment: true + scriptType: 'ps' + scriptLocation: 'inlineScript' + inlineScript: | + $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1 diff --git a/eng/common/templates-official/steps/source-index-stage1-publish.yml b/eng/common/templates-official/steps/source-index-stage1-publish.yml new file mode 100644 index 0000000000000..9b8b80942b5c3 --- /dev/null +++ b/eng/common/templates-official/steps/source-index-stage1-publish.yml @@ -0,0 +1,7 @@ +steps: +- template: /eng/common/core-templates/steps/source-index-stage1-publish.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/source-index-stage1-publish.yml b/eng/common/templates/steps/source-index-stage1-publish.yml new file mode 100644 index 0000000000000..182cec33a7bb7 --- /dev/null +++ b/eng/common/templates/steps/source-index-stage1-publish.yml @@ -0,0 +1,7 @@ +steps: +- template: /eng/common/core-templates/steps/source-index-stage1-publish.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/global.json b/global.json index 8387059e5bcfc..dfa530838f962 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "9.0.100-preview.7.24407.12" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24423.2", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24423.2", - "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24423.2", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.24461.3", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.24461.3", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.24461.3", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "9.0.0-rc.1.24410.5" From a833cfb101aff84715e56f517fc22f5ce17cf40c Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 12 Sep 2024 16:41:30 +0200 Subject: [PATCH 13/16] [WASI] System.Net.NameResolution (#107351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Köplinger --- .../Unix/System.Native/Interop.GetHostName.cs | 5 + .../Unix/System.Native/Interop.HostEntry.cs | 1 + .../Directory.Build.props | 3 +- .../src/System.Net.NameResolution.csproj | 41 +- .../src/System/Net/Dns.cs | 27 +- .../src/System/Net/NameResolutionPal.Unix.cs | 9 + .../System/Net/NameResolutionPal.Windows.cs | 3 + .../src/System/Net/NameResolutionTelemetry.cs | 4 +- .../FunctionalTests/GetHostAddressesTest.cs | 6 +- .../FunctionalTests/GetHostByAddressTest.cs | 1 + .../FunctionalTests/GetHostByNameTest.cs | 3 +- .../tests/FunctionalTests/GetHostEntryTest.cs | 21 + .../tests/FunctionalTests/LoggingTest.cs | 1 + .../tests/FunctionalTests/MetricsTest.cs | 1 + .../tests/FunctionalTests/ResolveTest.cs | 1 + ...Net.NameResolution.Functional.Tests.csproj | 3 +- .../tests/FunctionalTests/TelemetryTest.cs | 1 + .../tests/PalTests/NameResolutionPalTests.cs | 7 + ...System.Net.NameResolution.Pal.Tests.csproj | 7 +- .../System.Net.Primitives.Pal.Tests.csproj | 2 +- .../System/Environment.MachineName.cs | 2 +- src/libraries/tests.proj | 1 + src/native/libs/Common/pal_config.h.in | 3 + src/native/libs/System.Native/CMakeLists.txt | 3 +- .../libs/System.Native/pal_networking.c | 239 ++++++++-- .../libs/System.Native/pal_networking.h | 1 + .../libs/System.Native/pal_networking_wasi.c | 443 ------------------ src/native/libs/configure.cmake | 17 +- 28 files changed, 352 insertions(+), 504 deletions(-) delete mode 100644 src/native/libs/System.Native/pal_networking_wasi.c diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetHostName.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetHostName.cs index 5cc0c19772753..888c243521f83 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetHostName.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetHostName.cs @@ -14,6 +14,11 @@ internal static partial class Sys internal static unsafe string GetHostName() { + if (OperatingSystem.IsWasi()) + { + return "localhost"; + } + const int HOST_NAME_MAX = 255; const int ArrLength = HOST_NAME_MAX + 1; diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs index b8bc38524a59c..8d00d95ebf214 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs @@ -21,6 +21,7 @@ internal enum GetAddrInfoErrorFlags : int EAI_BADARG = 6, // One or more input arguments were invalid. EAI_NOMORE = 7, // No more entries are present in the list. EAI_MEMORY = 8, // Out of memory. + EAI_SYSTEM = 9, // Other system error; errno is set to indicate the error. } [StructLayout(LayoutKind.Sequential)] diff --git a/src/libraries/System.Net.NameResolution/Directory.Build.props b/src/libraries/System.Net.NameResolution/Directory.Build.props index bc799605d32ed..ce244cbea5619 100644 --- a/src/libraries/System.Net.NameResolution/Directory.Build.props +++ b/src/libraries/System.Net.NameResolution/Directory.Build.props @@ -3,7 +3,6 @@ Microsoft true - - browser;wasi + browser \ No newline at end of file diff --git a/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj b/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj index c5c8b4ffc9a58..582fe6cc88241 100644 --- a/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj +++ b/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj @@ -9,14 +9,14 @@ $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) - SR.SystemNetNameResolution_PlatformNotSupported - ExcludeApiList.PNSE.Browser.txt + SR.SystemNetNameResolution_PlatformNotSupported + ExcludeApiList.PNSE.Browser.txt - + @@ -80,6 +80,8 @@ Link="Common\Interop\CoreLib\Unix\Interop.Errors.cs" /> + - + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs index c8a526ccc4b3c..5bedc17d253f8 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs @@ -7,6 +7,7 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using System.Runtime.Versioning; namespace System.Net { @@ -37,6 +38,8 @@ public static string GetHostName() public static IPHostEntry GetHostEntry(IPAddress address) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(address); if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) @@ -68,7 +71,7 @@ public static IPHostEntry GetHostEntry(string hostNameOrAddress, AddressFamily f // See if it's an IP Address. IPHostEntry ipHostEntry; - if (IPAddress.TryParse(hostNameOrAddress, out IPAddress? address)) + if (NameResolutionPal.SupportsGetNameInfo && IPAddress.TryParse(hostNameOrAddress, out IPAddress? address)) { if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) { @@ -147,6 +150,8 @@ public static Task GetHostEntryAsync(string hostNameOrAddress, Addr public static Task GetHostEntryAsync(IPAddress address) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(address); if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) @@ -156,6 +161,8 @@ public static Task GetHostEntryAsync(IPAddress address) } return RunAsync(static (s, activity) => { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + IPHostEntry ipHostEntry = GetHostEntryCore((IPAddress)s, AddressFamily.Unspecified, activity); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info((IPAddress)s, $"{ipHostEntry} with {ipHostEntry.AddressList.Length} entries"); return ipHostEntry; @@ -170,6 +177,8 @@ public static IAsyncResult BeginGetHostEntry(string hostNameOrAddress, AsyncCall public static IPHostEntry EndGetHostEntry(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(asyncResult); return TaskToAsyncResult.End(asyncResult); @@ -244,6 +253,8 @@ public static IAsyncResult BeginGetHostAddresses(string hostNameOrAddress, Async public static IPAddress[] EndGetHostAddresses(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(asyncResult); return TaskToAsyncResult.End(asyncResult); @@ -269,6 +280,8 @@ public static IAsyncResult BeginGetHostByName(string hostName, AsyncCallback? re [Obsolete("EndGetHostByName has been deprecated. Use EndGetHostEntry instead.")] public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(asyncResult); return TaskToAsyncResult.End(asyncResult); @@ -277,6 +290,8 @@ public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult) [Obsolete("GetHostByAddress has been deprecated. Use GetHostEntry instead.")] public static IPHostEntry GetHostByAddress(string address) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(address); IPHostEntry ipHostEntry = GetHostEntryCore(IPAddress.Parse(address), AddressFamily.Unspecified); @@ -288,6 +303,8 @@ public static IPHostEntry GetHostByAddress(string address) [Obsolete("GetHostByAddress has been deprecated. Use GetHostEntry instead.")] public static IPHostEntry GetHostByAddress(IPAddress address) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(address); IPHostEntry ipHostEntry = GetHostEntryCore(address, AddressFamily.Unspecified); @@ -303,7 +320,7 @@ public static IPHostEntry Resolve(string hostName) // See if it's an IP Address. IPHostEntry ipHostEntry; - if (IPAddress.TryParse(hostName, out IPAddress? address) && + if (NameResolutionPal.SupportsGetNameInfo && IPAddress.TryParse(hostName, out IPAddress? address) && (address.AddressFamily != AddressFamily.InterNetworkV6 || SocketProtocolSupportPal.OSSupportsIPv6)) { try @@ -332,6 +349,8 @@ public static IAsyncResult BeginResolve(string hostName, AsyncCallback? requestC [Obsolete("EndResolve has been deprecated. Use EndGetHostEntry instead.")] public static IPHostEntry EndResolve(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + IPHostEntry ipHostEntry; try @@ -414,6 +433,8 @@ private static IPAddress[] GetHostAddressesCore(IPAddress address, AddressFamily // Does internal IPAddress reverse and then forward lookups (for Legacy and current public methods). private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAddresses, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + // Try to get the data for the host from its address. // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string // will only return that address and not the full list. @@ -500,7 +521,7 @@ private static Task GetHostEntryOrAddressesCoreAsync(string hostName, bool justR object asyncState; // See if it's an IP Address. - if (IPAddress.TryParse(hostName, out IPAddress? ipAddress)) + if (NameResolutionPal.SupportsGetNameInfo && IPAddress.TryParse(hostName, out IPAddress? ipAddress)) { if (throwOnIIPAny && (ipAddress.Equals(IPAddress.Any) || ipAddress.Equals(IPAddress.IPv6Any))) { diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs index 54ec640a3b071..c2924830c07be 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Runtime.Versioning; namespace System.Net { @@ -15,6 +16,9 @@ internal static partial class NameResolutionPal { public const bool SupportsGetAddrInfoAsync = false; + [UnsupportedOSPlatformGuard("wasi")] + public static bool SupportsGetNameInfo => !OperatingSystem.IsWasi(); + #pragma warning disable IDE0060 internal static Task? GetAddrInfoAsync(string hostName, bool justAddresses, AddressFamily family, CancellationToken cancellationToken) => throw new NotSupportedException(); @@ -39,6 +43,9 @@ private static SocketError GetSocketErrorForNativeError(int error) return SocketError.HostNotFound; case (int)Interop.Sys.GetAddrInfoErrorFlags.EAI_MEMORY: throw new OutOfMemoryException(); + case (int)Interop.Sys.GetAddrInfoErrorFlags.EAI_SYSTEM: + Debug.Fail($"Unexpected error: {error} errno: {Interop.Sys.GetErrNo()}"); + return SocketError.SocketError; default: Debug.Fail($"Unexpected error: {error}"); return SocketError.SocketError; @@ -146,6 +153,8 @@ public static unsafe SocketError TryGetAddrInfo(string name, bool justAddresses, public static unsafe string? TryGetNameInfo(IPAddress addr, out SocketError socketError, out int nativeErrorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + byte* buffer = stackalloc byte[Interop.Sys.NI_MAXHOST + 1 /*for null*/]; byte isIPv6; diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs index 72fc7685dffe9..a044e20461273 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; +using System.Runtime.Versioning; namespace System.Net { @@ -43,6 +44,8 @@ static void Initialize() } } + public const bool SupportsGetNameInfo = true; + public static unsafe SocketError TryGetAddrInfo(string name, bool justAddresses, AddressFamily addressFamily, out string? hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode) { Interop.Winsock.EnsureInitialized(); diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 07a252fbd250c..defa4da90564b 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -59,7 +59,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) private void ResolutionFailed() => WriteEvent(ResolutionFailedEventId); [NonEvent] - public static bool AnyDiagnosticsEnabled() => Log.IsEnabled() || NameResolutionMetrics.IsEnabled() || NameResolutionActivity.IsTracingEnabled(); + public static bool AnyDiagnosticsEnabled() => !OperatingSystem.IsWasi() && (Log.IsEnabled() || NameResolutionMetrics.IsEnabled() || NameResolutionActivity.IsTracingEnabled()); [NonEvent] public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long startingTimestamp = 0) @@ -91,6 +91,8 @@ public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long st [NonEvent] public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, object? answer, Exception? exception = null) { + if (OperatingSystem.IsWasi()) return; + if (!activity.Stop(answer, exception, out TimeSpan duration)) { // We stopped the System.Diagnostics.Activity at this point and neither metrics nor EventSource is enabled. diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs index 71820b8cc72f7..d1073db5d3986 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs @@ -69,14 +69,14 @@ public async Task Dns_GetHostAddressesAsync_NullHost_Fail() await Assert.ThrowsAsync(() => Dns.GetHostAddressesAsync(null)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void DnsBeginGetHostAddresses_BadName_Throws() { IAsyncResult asyncObject = Dns.BeginGetHostAddresses("BadName", null, null); Assert.ThrowsAny(() => Dns.EndGetHostAddresses(asyncObject)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void DnsBeginGetHostAddresses_BadIpString_ReturnsAddress() { IAsyncResult asyncObject = Dns.BeginGetHostAddresses("0.0.1.1", null, null); @@ -86,7 +86,7 @@ public void DnsBeginGetHostAddresses_BadIpString_ReturnsAddress() Assert.Equal(IPAddress.Parse("0.0.1.1"), results[0]); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void DnsBeginGetHostAddresses_MachineName_MatchesGetHostAddresses() { IAsyncResult asyncObject = Dns.BeginGetHostAddresses(TestSettings.LocalHost, null, null); diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByAddressTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByAddressTest.cs index a9072c6506faa..6a6b237b0d938 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByAddressTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByAddressTest.cs @@ -8,6 +8,7 @@ namespace System.Net.NameResolution.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public class GetHostByAddressTest { [Fact] diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByNameTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByNameTest.cs index 56f52afb1b7da..479a5cd39ac35 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByNameTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByNameTest.cs @@ -19,7 +19,7 @@ public void DnsObsoleteBeginGetHostByName_BadName_Throws() Assert.ThrowsAny(() => Dns.EndGetHostByName(asyncObject)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void DnsObsoleteBeginGetHostByName_IPv4String_ReturnsOnlyGivenIP() { IAsyncResult asyncObject = Dns.BeginGetHostByName(IPAddress.Loopback.ToString(), null, null); @@ -106,6 +106,7 @@ public void DnsObsoleteGetHostByName_IPv6String_ReturnsOnlyGivenIP() [ActiveIssue("https://github.com/dotnet/runtime/issues/1488", TestPlatforms.OSX)] [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/27622")] [ActiveIssue("https://github.com/dotnet/runtime/issues/51377", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107339", TestPlatforms.Wasi)] public void DnsObsoleteGetHostByName_EmptyString_ReturnsHostName() { IPHostEntry entry = Dns.GetHostByName(""); diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs index a4a7174897a39..c4988cef81672 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs @@ -148,10 +148,16 @@ public async Task Dns_GetHostEntry_NullStringHost_Fail() { Assert.Throws(() => Dns.GetHostEntry((string)null)); await Assert.ThrowsAsync(() => Dns.GetHostEntryAsync((string)null)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + public async Task Dns_GetHostEntry_NullStringHost_Fail_Obsolete() + { await Assert.ThrowsAsync(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, (string)null, null)); } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public async Task Dns_GetHostEntryAsync_NullIPAddressHost_Fail() { Assert.Throws(() => Dns.GetHostEntry((IPAddress)null)); @@ -168,6 +174,7 @@ public static IEnumerable GetInvalidAddresses() [Theory] [MemberData(nameof(GetInvalidAddresses))] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public async Task Dns_GetHostEntry_AnyIPAddress_Fail(IPAddress address) { Assert.Throws(() => Dns.GetHostEntry(address)); @@ -195,6 +202,7 @@ public async Task DnsGetHostEntry_MachineName_AllVariationsMatch() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public async Task DnsGetHostEntry_Loopback_AllVariationsMatch() { IPHostEntry syncResult = Dns.GetHostEntry(IPAddress.Loopback); @@ -216,6 +224,7 @@ public async Task DnsGetHostEntry_Loopback_AllVariationsMatch() [InlineData("Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee" + "eeeeend.Almost.There.Are.We.Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualll" + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Are")] // very long name but not too long + [ActiveIssue("https://github.com/dotnet/runtime/issues/107339", TestPlatforms.Wasi)] public async Task DnsGetHostEntry_BadName_ThrowsSocketException(string hostNameOrAddress) { Assert.ThrowsAny(() => Dns.GetHostEntry(hostNameOrAddress)); @@ -231,6 +240,14 @@ public async Task DnsGetHostEntry_BadName_ThrowsArgumentOutOfRangeException(stri { Assert.ThrowsAny(() => Dns.GetHostEntry(hostNameOrAddress)); await Assert.ThrowsAnyAsync(() => Dns.GetHostEntryAsync(hostNameOrAddress)); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [InlineData("Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee" + + "eeeeend.Almost.There.Are.We.Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualll" + + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Aret")] + public async Task DnsGetHostEntry_BadName_ThrowsArgumentOutOfRangeException_Obsolete(string hostNameOrAddress) + { await Assert.ThrowsAnyAsync(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null)); } @@ -238,6 +255,7 @@ public async Task DnsGetHostEntry_BadName_ThrowsArgumentOutOfRangeException(stri [InlineData(0)] [InlineData(1)] [InlineData(2)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107339", TestPlatforms.Wasi)] public async Task DnsGetHostEntry_LocalHost_ReturnsFqdnAndLoopbackIPs(int mode) { IPHostEntry entry = mode switch @@ -259,6 +277,9 @@ public async Task DnsGetHostEntry_LocalHost_ReturnsFqdnAndLoopbackIPs(int mode) [InlineData(2)] public async Task DnsGetHostEntry_LoopbackIP_MatchesGetHostEntryLoopbackString(int mode) { + if (OperatingSystem.IsWasi() && mode == 2) + throw new SkipTestException("mode 2 is not supported on WASI"); + IPAddress address = IPAddress.Loopback; IPHostEntry ipEntry = mode switch diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/LoggingTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/LoggingTest.cs index 920a5af60cf00..43f3db17b3e90 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/LoggingTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/LoggingTest.cs @@ -15,6 +15,7 @@ namespace System.Net.NameResolution.Tests using Configuration = System.Net.Test.Common.Configuration; [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI doesn't have event source yet")] public class LoggingTest { [Fact] diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/MetricsTest.cs index 0cafd974a4a20..ebee4d90e8dd1 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/MetricsTest.cs @@ -12,6 +12,7 @@ namespace System.Net.NameResolution.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "WASI doesn't have event source yet")] public class MetricsTest { private const string DnsLookupDuration = "dns.lookup.duration"; diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ResolveTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ResolveTest.cs index 071e9927ee9ff..814ec5cc6c267 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ResolveTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ResolveTest.cs @@ -46,6 +46,7 @@ public void DnsObsoleteResolve_BadName_Throws() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void DnsObsoleteResolve_BadIP_ReturnsIPasNameAndIP() { IPHostEntry entry = Dns.Resolve("0.0.1.1"); diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj index 182e5d9eba19b..9741c993ccdba 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj @@ -1,9 +1,10 @@ - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi true true true + true diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/TelemetryTest.cs index b88ad1188aedc..3da2983720572 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/TelemetryTest.cs @@ -12,6 +12,7 @@ namespace System.Net.NameResolution.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "WASI doesn't have event source yet")] public class TelemetryTest { [Fact] diff --git a/src/libraries/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs b/src/libraries/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs index 030f03c01eddf..e4049b1291990 100644 --- a/src/libraries/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs +++ b/src/libraries/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs @@ -61,6 +61,7 @@ private void LogUnixInfo() [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107339", TestPlatforms.Wasi)] public void TryGetAddrInfo_LocalHost(bool justAddresses) { SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", justAddresses, AddressFamily.Unspecified, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode); @@ -77,6 +78,7 @@ public void TryGetAddrInfo_LocalHost(bool justAddresses) [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107339", TestPlatforms.Wasi)] public void TryGetAddrInfo_EmptyHost(bool justAddresses) { SocketError error = NameResolutionPal.TryGetAddrInfo("", justAddresses, AddressFamily.Unspecified, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode); @@ -151,6 +153,7 @@ public void TryGetAddrInfo_UnknownHost(bool justAddresses) } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void TryGetNameInfo_LocalHost_IPv4() { SocketError error; @@ -161,6 +164,7 @@ public void TryGetNameInfo_LocalHost_IPv4() } [ConditionalFact(nameof(Ipv6LocalHostNameLookupNotBrokenByNrpRule))] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void TryGetNameInfo_LocalHost_IPv6() { SocketError error; @@ -176,6 +180,7 @@ public void TryGetNameInfo_LocalHost_IPv6() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void TryGetAddrInfo_LocalHost_TryGetNameInfo() { SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", justAddresses: false, AddressFamily.Unspecified, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode); @@ -247,6 +252,7 @@ public void TryGetAddrInfo_HostName_TryGetNameInfo() [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void TryGetNameInfo_LocalHost_IPv4_TryGetAddrInfo(bool justAddresses) { string name = NameResolutionPal.TryGetNameInfo(new IPAddress(new byte[] { 127, 0, 0, 1 }), out SocketError error, out _); @@ -262,6 +268,7 @@ public void TryGetNameInfo_LocalHost_IPv4_TryGetAddrInfo(bool justAddresses) [ConditionalTheory(nameof(Ipv6LocalHostNameLookupNotBrokenByNrpRule))] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "WASI has no getnameinfo")] public void TryGetNameInfo_LocalHost_IPv6_TryGetAddrInfo(bool justAddresses) { SocketError error; diff --git a/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj index 6e08a5f973e09..7daa5977519b0 100644 --- a/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj @@ -2,8 +2,9 @@ true ../../src/Resources/Strings.resx - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi true + true @@ -71,7 +72,9 @@ - + + - + + diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in index 4439e8cebfeaa..c8e43fa37dd6a 100644 --- a/src/native/libs/Common/pal_config.h.in +++ b/src/native/libs/Common/pal_config.h.in @@ -56,6 +56,9 @@ #cmakedefine01 HAVE_ETHTOOL_H #cmakedefine01 HAVE_SYS_POLL_H #cmakedefine01 HAVE_EPOLL +#cmakedefine01 HAVE_GETHOSTNAME +#cmakedefine01 HAVE_GETNAMEINFO +#cmakedefine01 HAVE_SOCKADDR_UN_SUN_PATH #cmakedefine01 HAVE_ACCEPT4 #cmakedefine01 HAVE_KQUEUE #cmakedefine01 HAVE_SENDFILE_4 diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index 4cac1051f6739..7e00e0ed0a271 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -24,6 +24,7 @@ set(NATIVE_SOURCES pal_io.c pal_maphardwaretype.c pal_memory.c + pal_networking.c pal_networkstatistics.c pal_random.c pal_runtimeinformation.c @@ -42,7 +43,6 @@ if (NOT CLR_CMAKE_TARGET_WASI) list (APPEND NATIVE_SOURCES pal_dynamicload.c pal_mount.c - pal_networking.c pal_process.c pal_signal.c pal_threading.c @@ -52,7 +52,6 @@ else() list (APPEND NATIVE_SOURCES pal_dynamicload_wasi.c pal_mount_wasi.c - pal_networking_wasi.c pal_process_wasi.c pal_signal_wasi.c pal_threading_wasi.c diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index dc727fe546504..82e3960e6fc33 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -34,7 +34,9 @@ #include #include #include +#if HAVE_NET_IF_H #include +#endif #include #include #include @@ -50,7 +52,9 @@ #include #endif #include +#ifdef HAVE_PWD_H #include +#endif #if HAVE_SENDFILE_4 #include #elif HAVE_SENDFILE_6 @@ -139,14 +143,11 @@ struct in_pktinfo #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif -enum -{ -#if defined(__APPLE__) && __APPLE__ - LINGER_OPTION_NAME = SO_LINGER_SEC -#else - LINGER_OPTION_NAME = SO_LINGER, +#if defined(__APPLE__) && __APPLE__ && defined(SO_LINGER_SEC) + #define LINGER_OPTION_NAME SO_LINGER_SEC +#elif defined(SO_LINGER) + #define LINGER_OPTION_NAME SO_LINGER #endif -}; enum { @@ -271,16 +272,17 @@ static void ConvertByteArrayToSockAddrIn6(struct sockaddr_in6* addr, const uint8 addr->sin6_family = AF_INET6; } -static void ConvertByteArrayToInAddr(struct in_addr* addr, const uint8_t* buffer, int32_t bufferLength) +static void ConvertInAddrToByteArray(uint8_t* buffer, int32_t bufferLength, const struct in_addr* addr) { assert(bufferLength == NUM_BYTES_IN_IPV4_ADDRESS); - memcpy_s(&addr->s_addr, NUM_BYTES_IN_IPV4_ADDRESS, buffer, (uint32_t)bufferLength); // Send back in network byte order. + memcpy_s(buffer, (uint32_t)bufferLength, &addr->s_addr, NUM_BYTES_IN_IPV4_ADDRESS); // Send back in network byte order. } -static void ConvertInAddrToByteArray(uint8_t* buffer, int32_t bufferLength, const struct in_addr* addr) +#if HAVE_GETNAMEINFO +static void ConvertByteArrayToInAddr(struct in_addr* addr, const uint8_t* buffer, int32_t bufferLength) { assert(bufferLength == NUM_BYTES_IN_IPV4_ADDRESS); - memcpy_s(buffer, (uint32_t)bufferLength, &addr->s_addr, NUM_BYTES_IN_IPV4_ADDRESS); // Send back in network byte order. + memcpy_s(&addr->s_addr, NUM_BYTES_IN_IPV4_ADDRESS, buffer, (uint32_t)bufferLength); // Send back in network byte order. } static void ConvertByteArrayToSockAddrIn(struct sockaddr_in* addr, const uint8_t* buffer, int32_t bufferLength) @@ -289,6 +291,7 @@ static void ConvertByteArrayToSockAddrIn(struct sockaddr_in* addr, const uint8_t addr->sin_family = AF_INET; } +#endif // HAVE_GETNAMEINFO static int32_t ConvertGetAddrInfoAndGetNameInfoErrorsToPal(int32_t error) { @@ -313,10 +316,12 @@ static int32_t ConvertGetAddrInfoAndGetNameInfoErrorsToPal(int32_t error) case EAI_NODATA: #endif return GetAddrInfoErrorFlags_EAI_NONAME; + case EAI_SYSTEM: + return GetAddrInfoErrorFlags_EAI_SYSTEM; + default: + assert_err(0, "Unknown AddrInfo error flag", error); + return -1; } - - assert_err(0, "Unknown AddrInfo error flag", error); - return -1; } static int32_t CopySockAddrToIPAddress(sockaddr* addr, sa_family_t family, IPAddress* ipAddress) @@ -546,6 +551,7 @@ typedef int32_t NativeFlagsType; typedef uint32_t NativeFlagsType; #endif +#if HAVE_GETNAMEINFO static inline NativeFlagsType ConvertGetNameInfoFlagsToNative(int32_t flags) { NativeFlagsType outFlags = 0; @@ -560,6 +566,7 @@ static inline NativeFlagsType ConvertGetNameInfoFlagsToNative(int32_t flags) return outFlags; } +#endif // HAVE_GETNAMEINFO int32_t SystemNative_GetNameInfo(const uint8_t* address, int32_t addressLength, @@ -570,6 +577,7 @@ int32_t SystemNative_GetNameInfo(const uint8_t* address, int32_t serviceLength, int32_t flags) { +#if HAVE_GETNAMEINFO assert(address != NULL); assert(addressLength > 0); assert((host != NULL) || (service != NULL)); @@ -606,6 +614,17 @@ int32_t SystemNative_GetNameInfo(const uint8_t* address, } return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result); +#else // HAVE_GETNAMEINFO + (void)address; + (void)addressLength, + (void)isIPv6, + (void)host, + (void)hostLength, + (void)service, + (void)serviceLength, + (void)flags; + return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(EAI_FAIL); +#endif // HAVE_GETNAMEINFO } int32_t SystemNative_GetDomainName(uint8_t* name, int32_t nameLength) @@ -652,11 +671,17 @@ int32_t SystemNative_GetDomainName(uint8_t* name, int32_t nameLength) int32_t SystemNative_GetHostName(uint8_t* name, int32_t nameLength) { +#if HAVE_GETHOSTNAME assert(name != NULL); assert(nameLength > 0); size_t unsignedSize = (uint32_t)nameLength; return gethostname((char*)name, unsignedSize); +#else // HAVE_GETHOSTNAME + (void)name; + (void)nameLength; + return Error_ENOTSUP; +#endif // HAVE_GETHOSTNAME } static bool IsInBounds(const void* void_baseAddr, size_t len, const void* void_valueAddr, size_t valueSize) @@ -907,6 +932,7 @@ SystemNative_SetIPv6Address(uint8_t* socketAddress, int32_t socketAddressLen, ui return Error_SUCCESS; } +#if defined(CMSG_SPACE) static int8_t IsStreamSocket(int socket) { int type; @@ -933,15 +959,23 @@ static void ConvertMessageHeaderToMsghdr(struct msghdr* header, const MessageHea header->msg_controllen = (uint32_t)messageHeader->ControlBufferLen; header->msg_flags = 0; } +#endif // CMSG_SPACE int32_t SystemNative_GetControlMessageBufferSize(int32_t isIPv4, int32_t isIPv6) { // Note: it is possible that the address family of the socket is neither // AF_INET nor AF_INET6. In this case both inputs will be 0 and // the control message buffer size should be zero. +#if defined(CMSG_SPACE) return (isIPv4 != 0 ? CMSG_SPACE(sizeof(struct in_pktinfo)) : 0) + (isIPv6 != 0 ? CMSG_SPACE(sizeof(struct in6_pktinfo)) : 0); +#else // CMSG_SPACE + (void)isIPv4; + (void)isIPv6; + return 0; +#endif // CMSG_SPACE } +#if defined(CMSG_SPACE) static int32_t GetIPv4PacketInformation(struct cmsghdr* controlMessage, IPPacketInformation* packetInfo) { assert(controlMessage != NULL); @@ -1020,6 +1054,7 @@ static struct cmsghdr* GET_CMSG_NXTHDR(struct msghdr* mhdr, struct cmsghdr* cmsg #pragma clang diagnostic pop #endif } +#endif // CMSG_SPACE int32_t SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isIPv4, IPPacketInformation* packetInfo) @@ -1029,6 +1064,7 @@ SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isI return 0; } +#if defined(CMSG_SPACE) struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, -1); @@ -1057,6 +1093,12 @@ SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isI } return 0; +#else // CMSG_SPACE + (void)messageHeader; + (void)isIPv4; + (void)packetInfo; + return Error_ENOTSUP; +#endif // CMSG_SPACE } static int8_t GetMulticastOptionName(int32_t multicastOption, int8_t isIPv6, int* optionName) @@ -1257,6 +1299,7 @@ int32_t SystemNative_GetLingerOption(intptr_t socket, LingerOption* option) return Error_EFAULT; } +#if defined(LINGER_OPTION_NAME) int fd = ToFileDescriptor(socket); struct linger opt; @@ -1271,6 +1314,11 @@ int32_t SystemNative_GetLingerOption(intptr_t socket, LingerOption* option) option->OnOff = opt.l_onoff; option->Seconds = opt.l_linger; return Error_SUCCESS; +#else // LINGER_OPTION_NAME + (void)socket; + (void)option; + return Error_ENOTSUP; +#endif // LINGER_OPTION_NAME } int32_t SystemNative_SetLingerOption(intptr_t socket, LingerOption* option) @@ -1285,6 +1333,7 @@ int32_t SystemNative_SetLingerOption(intptr_t socket, LingerOption* option) return Error_EINVAL; } +#if defined(LINGER_OPTION_NAME) int fd = ToFileDescriptor(socket); struct linger opt; @@ -1304,6 +1353,9 @@ int32_t SystemNative_SetLingerOption(intptr_t socket, LingerOption* option) #endif return err == 0 ? Error_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno); +#else // LINGER_OPTION_NAME + return Error_ENOTSUP; +#endif // LINGER_OPTION_NAME } static int32_t SetTimeoutOption(int32_t socket, int32_t millisecondsTimeout, int optionName) @@ -1333,32 +1385,62 @@ int32_t SystemNative_SetSendTimeout(intptr_t socket, int32_t millisecondsTimeout static int8_t ConvertSocketFlagsPalToPlatform(int32_t palFlags, int* platformFlags) { - const int32_t SupportedFlagsMask = + const int32_t SupportedFlagsMask = 0 #ifdef MSG_ERRQUEUE - SocketFlags_MSG_ERRQUEUE | + | SocketFlags_MSG_ERRQUEUE +#endif +#ifdef MSG_OOB + | SocketFlags_MSG_OOB +#endif +#ifdef MSG_PEEK + | SocketFlags_MSG_PEEK +#endif +#ifdef MSG_DONTWAIT + | SocketFlags_MSG_DONTWAIT +#endif +#ifdef MSG_DONTROUTE + | SocketFlags_MSG_DONTROUTE +#endif +#ifdef MSG_TRUNC + | SocketFlags_MSG_TRUNC #endif - SocketFlags_MSG_OOB | SocketFlags_MSG_PEEK | SocketFlags_MSG_DONTROUTE | SocketFlags_MSG_TRUNC | SocketFlags_MSG_CTRUNC | SocketFlags_MSG_DONTWAIT; +#ifdef MSG_CTRUNC + | SocketFlags_MSG_CTRUNC +#endif + ; if ((palFlags & ~SupportedFlagsMask) != 0) { return false; } - *platformFlags = ((palFlags & SocketFlags_MSG_OOB) == 0 ? 0 : MSG_OOB) | - ((palFlags & SocketFlags_MSG_PEEK) == 0 ? 0 : MSG_PEEK) | - ((palFlags & SocketFlags_MSG_DONTROUTE) == 0 ? 0 : MSG_DONTROUTE) | - ((palFlags & SocketFlags_MSG_DONTWAIT) == 0 ? 0 : MSG_DONTWAIT) | - ((palFlags & SocketFlags_MSG_TRUNC) == 0 ? 0 : MSG_TRUNC) | - ((palFlags & SocketFlags_MSG_CTRUNC) == 0 ? 0 : MSG_CTRUNC); + *platformFlags = 0 #ifdef MSG_ERRQUEUE - if ((palFlags & SocketFlags_MSG_ERRQUEUE) != 0) - { - *platformFlags |= MSG_ERRQUEUE; - } + | ((palFlags & SocketFlags_MSG_ERRQUEUE) == 0 ? 0 : MSG_ERRQUEUE) +#endif +#ifdef MSG_OOB + | ((palFlags & SocketFlags_MSG_OOB) == 0 ? 0 : MSG_OOB) +#endif +#ifdef MSG_PEEK + | ((palFlags & SocketFlags_MSG_PEEK) == 0 ? 0 : MSG_PEEK) +#endif +#ifdef MSG_DONTROUTE + | ((palFlags & SocketFlags_MSG_DONTROUTE) == 0 ? 0 : MSG_DONTROUTE) +#endif +#ifdef MSG_DONTWAIT + | ((palFlags & SocketFlags_MSG_DONTWAIT) == 0 ? 0 : MSG_DONTWAIT) +#endif +#ifdef MSG_TRUNC + | ((palFlags & SocketFlags_MSG_TRUNC) == 0 ? 0 : MSG_TRUNC) #endif +#ifdef MSG_CTRUNC + | ((palFlags & SocketFlags_MSG_CTRUNC) == 0 ? 0 : MSG_CTRUNC) +#endif + ; return true; } +#if defined(CMSG_SPACE) static int32_t ConvertSocketFlagsPlatformToPal(int platformFlags) { const int SupportedFlagsMask = MSG_OOB | MSG_DONTROUTE | MSG_TRUNC | MSG_CTRUNC; @@ -1370,6 +1452,7 @@ static int32_t ConvertSocketFlagsPlatformToPal(int platformFlags) ((platformFlags & MSG_TRUNC) == 0 ? 0 : SocketFlags_MSG_TRUNC) | ((platformFlags & MSG_CTRUNC) == 0 ? 0 : SocketFlags_MSG_CTRUNC); } +#endif // CMSG_SPACE int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* received) { @@ -1469,10 +1552,14 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade return Error_ENOTSUP; } + ssize_t res; +#if !defined(CMSG_SPACE) + // TODO https://github.com/dotnet/runtime/issues/98957 + return Error_ENOTSUP; +#else // !CMSG_SPACE struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, fd); - ssize_t res; while ((res = recvmsg(fd, &header, socketFlags)) < 0 && errno == EINTR); assert(header.msg_name == messageHeader->SocketAddress); // should still be the same location as set in ConvertMessageHeaderToMsghdr @@ -1494,6 +1581,7 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade *received = 0; return SystemNative_ConvertErrorPlatformToPal(errno); +#endif // !CMSG_SPACE } int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent) @@ -1547,10 +1635,14 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, return Error_ENOTSUP; } +#if !defined(CMSG_SPACE) + // TODO https://github.com/dotnet/runtime/issues/98957 + return Error_ENOTSUP; +#else // !CMSG_SPACE + ssize_t res; struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, fd); - ssize_t res; #if defined(__APPLE__) && __APPLE__ // possible OSX kernel bug: https://github.com/dotnet/runtime/issues/27221 // According to https://github.com/dotnet/runtime/issues/63291 the EPROTOTYPE may be @@ -1568,6 +1660,7 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, *sent = 0; return SystemNative_ConvertErrorPlatformToPal(errno); +#endif // !CMSG_SPACE } int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen, intptr_t* acceptedSocket) @@ -1699,7 +1792,7 @@ int32_t SystemNative_Connectx(intptr_t socket, uint8_t* socketAddress, int32_t s } #endif // avoid possible warning about unused parameters - (void*)data; + (void)data; (void)dataLen; (void)tfo; sent = 0; @@ -1791,9 +1884,11 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socket switch (socketOptionName) { +#if defined(SO_DEBUG) case SocketOptionName_SO_DEBUG: *optName = SO_DEBUG; return true; +#endif case SocketOptionName_SO_ACCEPTCONN: *optName = SO_ACCEPTCONN; @@ -1807,23 +1902,31 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socket *optName = SO_KEEPALIVE; return true; +#if defined(SO_DONTROUTE) case SocketOptionName_SO_DONTROUTE: *optName = SO_DONTROUTE; return true; +#endif +#if defined(SO_BROADCAST) case SocketOptionName_SO_BROADCAST: *optName = SO_BROADCAST; return true; +#endif // case SocketOptionName_SO_USELOOPBACK: +#if defined(SO_LINGER) case SocketOptionName_SO_LINGER: *optName = SO_LINGER; return true; +#endif +#if defined(SO_OOBINLINE) case SocketOptionName_SO_OOBINLINE: *optName = SO_OOBINLINE; return true; +#endif // case SocketOptionName_SO_DONTLINGER: @@ -1837,14 +1940,18 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socket *optName = SO_RCVBUF; return true; +#if defined(SO_SNDLOWAT) case SocketOptionName_SO_SNDLOWAT: *optName = SO_SNDLOWAT; return true; +#endif +#if defined(SO_RCVLOWAT) case SocketOptionName_SO_RCVLOWAT: *optName = SO_RCVLOWAT; return true; +#endif case SocketOptionName_SO_SNDTIMEO: *optName = SO_SNDTIMEO; return true; @@ -2064,9 +2171,11 @@ static bool TryConvertSocketTypePlatformToPal(int platformSocketType, int32_t* p *palSocketType = SocketType_SOCK_DGRAM; return true; +#if defined(SOCK_RAW) case SOCK_RAW: *palSocketType = SocketType_SOCK_RAW; return true; +#endif // SOCK_RAW #ifdef SOCK_RDM case SOCK_RDM: @@ -2074,9 +2183,11 @@ static bool TryConvertSocketTypePlatformToPal(int platformSocketType, int32_t* p return true; #endif +#if defined(SOCK_SEQPACKET) case SOCK_SEQPACKET: *palSocketType = SocketType_SOCK_SEQPACKET; return true; +#endif // SOCK_SEQPACKET default: *palSocketType = (int32_t)platformSocketType; @@ -2336,9 +2447,11 @@ static bool TryConvertSocketTypePalToPlatform(int32_t palSocketType, int* platfo *platformSocketType = SOCK_DGRAM; return true; +#if defined(SOCK_RAW) case SocketType_SOCK_RAW: *platformSocketType = SOCK_RAW; return true; +#endif // SOCK_RAW #ifdef SOCK_RDM case SocketType_SOCK_RDM: @@ -2346,9 +2459,11 @@ static bool TryConvertSocketTypePalToPlatform(int32_t palSocketType, int* platfo return true; #endif +#if defined(SOCK_SEQPACKET) case SocketType_SOCK_SEQPACKET: *platformSocketType = SOCK_SEQPACKET; return true; +#endif // SOCK_SEQPACKET default: *platformSocketType = (int)palSocketType; @@ -2392,9 +2507,11 @@ static bool TryConvertProtocolTypePalToPlatform(int32_t palAddressFamily, int32_ *platformProtocolType = 0; return true; +#if defined(IPPROTO_ICMP) case ProtocolType_PT_ICMP: *platformProtocolType = IPPROTO_ICMP; return true; +#endif case ProtocolType_PT_TCP: *platformProtocolType = IPPROTO_TCP; @@ -2404,9 +2521,11 @@ static bool TryConvertProtocolTypePalToPlatform(int32_t palAddressFamily, int32_ *platformProtocolType = IPPROTO_UDP; return true; +#if defined(IPPROTO_IGMP) case ProtocolType_PT_IGMP: *platformProtocolType = IPPROTO_IGMP; return true; +#endif case ProtocolType_PT_RAW: *platformProtocolType = IPPROTO_RAW; @@ -2424,10 +2543,12 @@ static bool TryConvertProtocolTypePalToPlatform(int32_t palAddressFamily, int32_ *platformProtocolType = 0; return true; +#if defined(IPPROTO_ICMPV6) case ProtocolType_PT_ICMPV6: case ProtocolType_PT_ICMP: *platformProtocolType = IPPROTO_ICMPV6; return true; +#endif case ProtocolType_PT_TCP: *platformProtocolType = IPPROTO_TCP; @@ -2437,29 +2558,39 @@ static bool TryConvertProtocolTypePalToPlatform(int32_t palAddressFamily, int32_ *platformProtocolType = IPPROTO_UDP; return true; +#if defined(IPPROTO_IGMP) case ProtocolType_PT_IGMP: *platformProtocolType = IPPROTO_IGMP; return true; +#endif case ProtocolType_PT_RAW: *platformProtocolType = IPPROTO_RAW; return true; +#if defined(IPPROTO_DSTOPTS) case ProtocolType_PT_DSTOPTS: *platformProtocolType = IPPROTO_DSTOPTS; return true; +#endif +#if defined(IPPROTO_NONE) case ProtocolType_PT_NONE: *platformProtocolType = IPPROTO_NONE; return true; +#endif +#if defined(IPPROTO_ROUTING) case ProtocolType_PT_ROUTING: *platformProtocolType = IPPROTO_ROUTING; return true; +#endif +#if defined(IPPROTO_FRAGMENT) case ProtocolType_PT_FRAGMENT: *platformProtocolType = IPPROTO_FRAGMENT; return true; +#endif default: *platformProtocolType = (int)palProtocolType; @@ -2515,9 +2646,11 @@ static bool TryConvertProtocolTypePlatformToPal(int32_t palAddressFamily, int pl *palProtocolType = ProtocolType_PT_UNSPECIFIED; return true; +#if defined(IPPROTO_ICMP) case IPPROTO_ICMP: *palProtocolType = ProtocolType_PT_ICMP; return true; +#endif case IPPROTO_TCP: *palProtocolType = ProtocolType_PT_TCP; @@ -2527,9 +2660,11 @@ static bool TryConvertProtocolTypePlatformToPal(int32_t palAddressFamily, int pl *palProtocolType = ProtocolType_PT_UDP; return true; +#if defined(IPPROTO_IGMP) case IPPROTO_IGMP: *palProtocolType = ProtocolType_PT_IGMP; return true; +#endif case IPPROTO_RAW: *palProtocolType = ProtocolType_PT_RAW; @@ -2547,9 +2682,11 @@ static bool TryConvertProtocolTypePlatformToPal(int32_t palAddressFamily, int pl *palProtocolType = ProtocolType_PT_UNSPECIFIED; return true; +#if defined(IPPROTO_ICMPV6) case IPPROTO_ICMPV6: *palProtocolType = ProtocolType_PT_ICMPV6; return true; +#endif case IPPROTO_TCP: *palProtocolType = ProtocolType_PT_TCP; @@ -2559,29 +2696,39 @@ static bool TryConvertProtocolTypePlatformToPal(int32_t palAddressFamily, int pl *palProtocolType = ProtocolType_PT_UDP; return true; +#if defined(IPPROTO_IGMP) case IPPROTO_IGMP: *palProtocolType = ProtocolType_PT_IGMP; return true; +#endif case IPPROTO_RAW: *palProtocolType = ProtocolType_PT_RAW; return true; +#if defined(IPPROTO_DSTOPTS) case IPPROTO_DSTOPTS: *palProtocolType = ProtocolType_PT_DSTOPTS; return true; +#endif +#if defined(IPPROTO_NONE) case IPPROTO_NONE: *palProtocolType = ProtocolType_PT_NONE; return true; +#endif +#if defined(IPPROTO_ROUTING) case IPPROTO_ROUTING: *palProtocolType = ProtocolType_PT_ROUTING; return true; +#endif +#if defined(IPPROTO_FRAGMENT) case IPPROTO_FRAGMENT: *palProtocolType = ProtocolType_PT_FRAGMENT; return true; +#endif default: *palProtocolType = (int)platformProtocolType; @@ -2723,6 +2870,7 @@ int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int3 int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* atMark) { +#if defined(SIOCATMARK) if (atMark == NULL) { return Error_EFAULT; @@ -2741,6 +2889,9 @@ int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* atMark) *atMark = (int32_t)result; return Error_SUCCESS; +#else // SIOCATMARK + return Error_ENOTSUP; +#endif // SIOCATMARK } int32_t SystemNative_GetBytesAvailable(intptr_t socket, int32_t* available) @@ -2847,11 +2998,15 @@ int32_t SystemNative_Select(int* readFds, int readFdsCount, int* writeFds, int w return Error_SUCCESS; #else // avoid unused parameters warnings - (void*)readFds; - (void*)writeFds; - (void*)errorFds; - (void*)triggered; - readFdsCount + writeFdsCount + errorFdsCount + microseconds + maxFd; + (void)readFds; + (void)writeFds; + (void)errorFds; + (void)triggered; + (void)readFdsCount; + (void)writeFdsCount; + (void)errorFdsCount; + (void)microseconds; + (void)maxFd; return SystemNative_ConvertErrorPlatformToPal(ENOTSUP); #endif } @@ -3151,10 +3306,6 @@ static int32_t WaitForSocketEventsInner(int32_t port, SocketEvent* buffer, int32 #else static const size_t SocketEventBufferElementSize = 0; -static SocketEvents GetSocketEvents(int16_t filter, uint16_t flags) -{ - return SocketEvents_SA_NONE; -} static int32_t CloseSocketEventPortInner(int32_t port) { return Error_ENOSYS; @@ -3268,8 +3419,13 @@ void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, i struct sockaddr_un domainSocket; +#if HAVE_SOCKADDR_UN_SUN_PATH *pathOffset = offsetof(struct sockaddr_un, sun_path); *pathSize = sizeof(domainSocket.sun_path); +#else // HAVE_SOCKADDR_UN_SUN_PATH + *pathOffset = 0; + *pathSize = 0; +#endif // HAVE_SOCKADDR_UN_SUN_PATH *addressSize = sizeof(domainSocket); } @@ -3449,8 +3605,13 @@ int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, i uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) { +#if HAVE_NET_IF_H assert(interfaceName != NULL); if (interfaceName[0] == '%') interfaceName++; return if_nametoindex(interfaceName); +#else // HAVE_NET_IF_H + (void)interfaceName; + return Error_ENOTSUP; +#endif // HAVE_NET_IF_H } diff --git a/src/native/libs/System.Native/pal_networking.h b/src/native/libs/System.Native/pal_networking.h index a0904f295267d..8044ce00b0266 100644 --- a/src/native/libs/System.Native/pal_networking.h +++ b/src/native/libs/System.Native/pal_networking.h @@ -24,6 +24,7 @@ typedef enum GetAddrInfoErrorFlags_EAI_BADARG = 6, // One or more input arguments were invalid. GetAddrInfoErrorFlags_EAI_NOMORE = 7, // No more entries are present in the list. GetAddrInfoErrorFlags_EAI_MEMORY = 8, // Out of memory. + GetAddrInfoErrorFlags_EAI_SYSTEM = 9, // Other system error; errno is set to indicate the error. } GetAddrInfoErrorFlags; /** diff --git a/src/native/libs/System.Native/pal_networking_wasi.c b/src/native/libs/System.Native/pal_networking_wasi.c deleted file mode 100644 index baeb6494b31e7..0000000000000 --- a/src/native/libs/System.Native/pal_networking_wasi.c +++ /dev/null @@ -1,443 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_config.h" -#include "pal_networking.h" -#include "pal_safecrt.h" -#include "pal_utilities.h" -#include -#include - -#include -#include -int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t addressFamily, HostEntry* entry) -{ - return -1; -} - -void SystemNative_FreeHostEntry(HostEntry* entry) -{ - if (entry != NULL) - { - free(entry->CanonicalName); - free(entry->IPAddressList); - - entry->CanonicalName = NULL; - entry->IPAddressList = NULL; - entry->IPAddressCount = 0; - } -} - -int32_t SystemNative_GetNameInfo(const uint8_t* address, - int32_t addressLength, - int8_t isIPv6, - uint8_t* host, - int32_t hostLength, - uint8_t* service, - int32_t serviceLength, - int32_t flags) -{ - assert(address != NULL); - assert(addressLength > 0); - assert((host != NULL) || (service != NULL)); - assert((hostLength > 0) || (serviceLength > 0)); - - return Error_EINVAL; -} - -int32_t SystemNative_GetDomainName(uint8_t* name, int32_t nameLength) -{ - assert(name != NULL); - assert(nameLength > 0); - return Error_EFAULT; -} - -int32_t SystemNative_GetHostName(uint8_t* name, int32_t nameLength) -{ - assert(name != NULL); - assert(nameLength > 0); - - size_t unsignedSize = (uint32_t)nameLength; - return gethostname((char*)name, unsignedSize); -} - -int32_t SystemNative_GetSocketAddressSizes(int32_t* ipv4SocketAddressSize, int32_t* ipv6SocketAddressSize, int32_t*udsSocketAddressSize, int* maxSocketAddressSize) -{ - return Error_EFAULT; -} - -int32_t SystemNative_GetAddressFamily(const uint8_t* socketAddress, int32_t socketAddressLen, int32_t* addressFamily) -{ - return Error_EFAULT; -} - -int32_t SystemNative_SetAddressFamily(uint8_t* socketAddress, int32_t socketAddressLen, int32_t addressFamily) -{ - return Error_EFAULT; -} - -int32_t SystemNative_GetPort(const uint8_t* socketAddress, int32_t socketAddressLen, uint16_t* port) -{ - return Error_EFAULT; -} - -int32_t SystemNative_SetPort(uint8_t* socketAddress, int32_t socketAddressLen, uint16_t port) -{ - return Error_EFAULT; -} - -int32_t SystemNative_GetIPv4Address(const uint8_t* socketAddress, int32_t socketAddressLen, uint32_t* address) -{ - return Error_EFAULT; -} - -int32_t SystemNative_SetIPv4Address(uint8_t* socketAddress, int32_t socketAddressLen, uint32_t address) -{ - return Error_EFAULT; -} - -int32_t SystemNative_GetIPv6Address( - const uint8_t* socketAddress, int32_t socketAddressLen, uint8_t* address, int32_t addressLen, uint32_t* scopeId) -{ - return Error_EFAULT; -} - -int32_t -SystemNative_SetIPv6Address(uint8_t* socketAddress, int32_t socketAddressLen, uint8_t* address, int32_t addressLen, uint32_t scopeId) -{ - return Error_EFAULT; -} - -int32_t SystemNative_GetControlMessageBufferSize(int32_t isIPv4, int32_t isIPv6) -{ - return Error_EFAULT; -} - - -int32_t -SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isIPv4, IPPacketInformation* packetInfo) -{ - if (messageHeader == NULL || packetInfo == NULL) - { - return 0; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetIPv4MulticastOption(intptr_t socket, int32_t multicastOption, IPv4MulticastOption* option) -{ - return Error_EINVAL; -} - -int32_t SystemNative_SetIPv4MulticastOption(intptr_t socket, int32_t multicastOption, IPv4MulticastOption* option) -{ - if (option == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetIPv6MulticastOption(intptr_t socket, int32_t multicastOption, IPv6MulticastOption* option) -{ - if (option == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_SetIPv6MulticastOption(intptr_t socket, int32_t multicastOption, IPv6MulticastOption* option) -{ - if (option == NULL) - { - return Error_EFAULT; - } - return Error_EINVAL; -} - - -int32_t SystemNative_GetLingerOption(intptr_t socket, LingerOption* option) -{ - if (option == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_SetLingerOption(intptr_t socket, LingerOption* option) -{ - if (option == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_SetReceiveTimeout(intptr_t socket, int32_t millisecondsTimeout) -{ - return Error_EINVAL; -} - -int32_t SystemNative_SetSendTimeout(intptr_t socket, int32_t millisecondsTimeout) -{ - return Error_EINVAL; -} -int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* received) -{ - if (buffer == NULL || bufferLen < 0 || received == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* received) -{ - if (messageHeader == NULL || received == NULL || messageHeader->SocketAddressLen < 0 || - messageHeader->ControlBufferLen < 0 || messageHeader->IOVectorCount < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent) -{ - return Error_EINVAL; -} - -int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* sent) -{ - return Error_EINVAL; -} - -int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen, intptr_t* acceptedSocket) -{ - if (socketAddress == NULL || socketAddressLen == NULL || acceptedSocket == NULL || *socketAddressLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_Bind(intptr_t socket, int32_t protocolType, uint8_t* socketAddress, int32_t socketAddressLen) -{ - if (socketAddress == NULL || socketAddressLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_Connect(intptr_t socket, uint8_t* socketAddress, int32_t socketAddressLen) -{ - return Error_EINVAL; -} - -int32_t SystemNative_GetPeerName(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen) -{ - if (socketAddress == NULL || socketAddressLen == NULL || *socketAddressLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetSockName(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen) -{ - if (socketAddress == NULL || socketAddressLen == NULL || *socketAddressLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_Listen(intptr_t socket, int32_t backlog) -{ - return Error_EINVAL; -} - -int32_t SystemNative_Shutdown(intptr_t socket, int32_t socketShutdown) -{ - return Error_EINVAL; -} - -int32_t SystemNative_GetSocketErrorOption(intptr_t socket, int32_t* error) -{ - if (error == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetSockOpt( - intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t* optionLen) -{ - if (optionLen == NULL || *optionLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetRawSockOpt( - intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t* optionLen) -{ - if (optionLen == NULL || *optionLen < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t -SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t optionLen) -{ - return Error_EINVAL; -} - -int32_t SystemNative_SetRawSockOpt( - intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t optionLen) -{ - if (optionLen < 0 || optionValue == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t protocolType, intptr_t* createdSocket) -{ - if (createdSocket == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType, int32_t* isListening) -{ - if (addressFamily == NULL || socketType == NULL || protocolType == NULL || isListening == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* atMark) -{ - if (atMark == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_GetBytesAvailable(intptr_t socket, int32_t* available) -{ - if (available == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_CreateSocketEventPort(intptr_t* port) -{ - if (port == NULL) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_CloseSocketEventPort(intptr_t port) -{ - return Error_EINVAL; -} - -int32_t SystemNative_CreateSocketEventBuffer(int32_t count, SocketEvent** buffer) -{ - if (buffer == NULL || count < 0) - { - return Error_EFAULT; - } - - return Error_EINVAL; -} - -int32_t SystemNative_FreeSocketEventBuffer(SocketEvent* buffer) -{ - free(buffer); - return Error_SUCCESS; -} - -int32_t -SystemNative_TryChangeSocketEventRegistration(intptr_t port, intptr_t socket, int32_t currentEvents, int32_t newEvents, uintptr_t data) -{ - return Error_EINVAL; -} - -int32_t SystemNative_WaitForSocketEvents(intptr_t port, SocketEvent* buffer, int32_t* count) -{ - return Error_EINVAL; -} - -int32_t SystemNative_PlatformSupportsDualModeIPv4PacketInfo(void) -{ - return 0; -} - -void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, int32_t* addressSize) -{ - *pathOffset = -1; - *pathSize = -1; - *addressSize = -1; -} - -int32_t SystemNative_GetMaximumAddressSize(void) -{ - return sizeof(struct sockaddr_storage); -} - -int32_t SystemNative_Disconnect(intptr_t socket) -{ - return Error_EINVAL; -} - -int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, int64_t count, int64_t* sent) -{ - assert(sent != NULL); - - return Error_EINVAL; -} - -uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) -{ - assert(interfaceName != NULL); - return Error_EINVAL; -} - diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake index 477f9f1f14a03..945fbed855ce8 100644 --- a/src/native/libs/configure.cmake +++ b/src/native/libs/configure.cmake @@ -458,6 +458,18 @@ check_symbol_exists( sys/epoll.h HAVE_EPOLL) +check_symbol_exists( + gethostname + unistd.h + HAVE_GETHOSTNAME) + +check_symbol_exists( + getnameinfo + netdb.h + HAVE_GETNAMEINFO) + +check_struct_has_member("struct sockaddr_un" sun_path "sys/types.h;sys/un.h" HAVE_SOCKADDR_UN_SUN_PATH) + check_symbol_exists( accept4 sys/socket.h @@ -562,7 +574,10 @@ elseif(CLR_CMAKE_TARGET_ANDROID) unset(HAVE_ALIGNED_ALLOC) # only exists on newer Android set(HAVE_CLOCK_MONOTONIC 1) set(HAVE_CLOCK_REALTIME 1) -elseif(CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) +elseif(CLR_CMAKE_TARGET_WASI) + set(HAVE_FORK 0) + unset(HAVE_GETNAMEINFO) # WASIp2 libc has empty function with TODO and abort() +elseif(CLR_CMAKE_TARGET_BROWSER) set(HAVE_FORK 0) else() check_symbol_exists( From d62199d0035ef82921fd337143ae13f8626b9b48 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 12 Sep 2024 08:54:35 -0700 Subject: [PATCH 14/16] Remove ILCompiler package reference (#107583) It doesn't look like we need the newest version of the package anymore. This configuration (using the package instead of the SDK version) can be dangerous because it causes a split between the version built against vs. the version AOT'd against. --- eng/Version.Details.xml | 4 ---- eng/Versions.props | 2 -- eng/liveBuilds.targets | 9 +++++++++ src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj | 6 ------ src/native/managed/native-library.props | 6 ------ 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b24be66d02d79..ce83b3b27fccc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -304,10 +304,6 @@ 7cb32e193a55a95c74fc3bd56501b951b48b700f - - https://github.com/dotnet/runtime - 7cb32e193a55a95c74fc3bd56501b951b48b700f - https://github.com/dotnet/runtime 7cb32e193a55a95c74fc3bd56501b951b48b700f diff --git a/eng/Versions.props b/eng/Versions.props index 6103f74a4c707..0a9237e261641 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -212,8 +212,6 @@ 8.0.0-preview-20230918.1 0.11.5-alpha.24460.1 - - 9.0.0-rc.1.24410.5 10.0.0-alpha.1.24459.2 diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 514b61cc1b91a..8a70af36f27e7 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -58,6 +58,15 @@ $([MSBuild]::NormalizePath('$(CoreCLRArtifactsPath)', 'corehost', 'singlefilehost$(ExeSuffix)')) + + + true + + + + + + diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj index ffab9cbb1289b..48c4f381d0864 100644 --- a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj @@ -15,14 +15,8 @@ true true true - true - - - - - false - true Guard @@ -34,9 +33,4 @@ - - - - - From 07d525e60606b4fc187daf296182c16a2464cd9f Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 12 Sep 2024 09:34:56 -0700 Subject: [PATCH 15/16] Move load level tracking and checks from `DomainAssembly` to `Assembly` (#107697) - Make `AppDomain::LoadDomainAssembly` return Assembly, rename to `LoadAssembly` - Remove `Assembly::CheckLoaded/EnsureLoaded` - not used - Remove `Assembly::IsVisibleToDebugger` - always true - Remove `Assembly::ExInfo` - always just wraps `Exception` --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 7 +- src/coreclr/debug/daccess/request.cpp | 8 +- src/coreclr/vm/appdomain.cpp | 161 +++++++++---------- src/coreclr/vm/appdomain.hpp | 58 +++---- src/coreclr/vm/assembly.cpp | 73 ++++----- src/coreclr/vm/assembly.hpp | 155 ++++++++++++++---- src/coreclr/vm/assemblynative.cpp | 3 +- src/coreclr/vm/assemblyspec.cpp | 5 +- src/coreclr/vm/ceeload.cpp | 27 ++-- src/coreclr/vm/domainassembly.cpp | 144 +++++------------ src/coreclr/vm/domainassembly.h | 192 ----------------------- src/coreclr/vm/eventtrace_bulktype.cpp | 6 +- src/coreclr/vm/loaderallocator.cpp | 2 +- src/coreclr/vm/multicorejit.cpp | 6 +- src/coreclr/vm/peassembly.cpp | 6 +- src/coreclr/vm/profilingenumerators.cpp | 4 +- src/coreclr/vm/reflectioninvocation.cpp | 8 +- 17 files changed, 331 insertions(+), 534 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 77ed5df2327cc..28b31c4116a72 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -4425,11 +4425,6 @@ void DacDbiInterfaceImpl::EnumerateAssembliesInAppDomain( while (iterator.Next(pDomainAssembly.This())) { - if (!pDomainAssembly->IsVisibleToDebugger()) - { - continue; - } - VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr(); vmDomainAssembly.SetHostPtr(pDomainAssembly); @@ -4454,7 +4449,7 @@ void DacDbiInterfaceImpl::EnumerateModulesInAssembly( if (pDomainAssembly->GetModule()->IsVisibleToDebugger()) { // If domain assembly isn't yet loaded, just return - if (!pDomainAssembly->IsLoaded()) + if (!pDomainAssembly->GetAssembly()->IsLoaded()) return; VMPTR_DomainAssembly vmDomainAssembly = VMPTR_DomainAssembly::NullPtr(); diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 1b886e300471f..2d675c3372802 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -2859,7 +2859,7 @@ ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData * while (i.Next(pDomainAssembly.This())) { - if (pDomainAssembly->IsLoaded()) + if (pDomainAssembly->GetAssembly()->IsLoaded()) { appdomainData->AssemblyCount++; } @@ -2978,9 +2978,9 @@ ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS { while (i.Next(pDomainAssembly.This()) && (n < count)) { - if (pDomainAssembly->IsLoaded()) + CollectibleAssemblyHolder pAssembly = pDomainAssembly->GetAssembly(); + if (pAssembly->IsLoaded()) { - CollectibleAssemblyHolder pAssembly = pDomainAssembly->GetAssembly(); // Note: DAC doesn't need to keep the assembly alive - see code:CollectibleAssemblyHolder#CAH_DAC values[n++] = HOST_CDADDR(pAssembly.Extract()); } @@ -2989,7 +2989,7 @@ ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS else { while (i.Next(pDomainAssembly.This())) - if (pDomainAssembly->IsLoaded()) + if (pDomainAssembly->GetAssembly()->IsLoaded()) n++; } diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index c53e4a1c20ec8..051b7c2a2005f 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -914,7 +914,7 @@ void SystemDomain::Init() PreallocateSpecialObjects(); // Finish loading CoreLib now. - m_pSystemAssembly->GetDomainAssembly()->EnsureActive(); + m_pSystemAssembly->EnsureActive(); // Set AwareLock's offset of the holding OS thread ID field into ThreadBlockingInfo's static field. That can be used // when doing managed debugging to get the OS ID of the thread holding the lock. The offset is currently not zero, and @@ -1014,7 +1014,7 @@ void SystemDomain::LoadBaseSystemClasses() // Only partially load the system assembly. Other parts of the code will want to access // the globals in this function before finishing the load. - m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_BEFORE_TYPE_LOAD)->GetAssembly(); + m_pSystemAssembly = DefaultDomain()->LoadAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_BEFORE_TYPE_LOAD); // Set up binder for CoreLib CoreLibBinder::AttachModule(m_pSystemAssembly->GetModule()); @@ -1888,7 +1888,7 @@ DispIDCache* AppDomain::SetupRefDispIDCache() #endif // FEATURE_COMINTEROP -FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssembly, DomainAssembly *pDomainAssembly) +FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssembly, Assembly *pAssembly) { CONTRACTL { @@ -1901,7 +1901,7 @@ FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssemb } CONTRACTL_END; - NewHolder result(new FileLoadLock(pLock, pPEAssembly, pDomainAssembly)); + NewHolder result(new FileLoadLock(pLock, pPEAssembly, pAssembly)); pLock->AddElement(result); result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel. @@ -1921,10 +1921,10 @@ FileLoadLock::~FileLoadLock() ((PEAssembly *) m_data)->Release(); } -DomainAssembly *FileLoadLock::GetDomainAssembly() +Assembly *FileLoadLock::GetAssembly() { LIMITED_METHOD_CONTRACT; - return m_pDomainAssembly; + return m_pAssembly; } FileLoadLevel FileLoadLock::GetLoadLevel() @@ -2000,7 +2000,7 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) if (level > m_level) { // Must complete each level in turn, unless we have an error - CONSISTENCY_CHECK(m_pDomainAssembly->IsError() || (level == (m_level+1))); + CONSISTENCY_CHECK(m_pAssembly->IsError() || (level == (m_level+1))); // Remove the lock from the list if the load is completed if (level >= FILE_ACTIVE) { @@ -2014,9 +2014,9 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) m_pList->Unlink(this); _ASSERTE(fDbgOnly_SuccessfulUnlink); - m_pDomainAssembly->ClearLoading(); + m_pAssembly->ClearLoading(); - CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainAssembly) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create. + CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadAssembly) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create. m_level = (FileLoadLevel)level; @@ -2025,7 +2025,7 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) // we depend on the DomainAssembly's load level being up to date. Hence we must update the load // level while the m_pList lock is held. if (success) - m_pDomainAssembly->SetLoadLevel(level); + m_pAssembly->SetLoadLevel(level); } @@ -2037,7 +2037,7 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) m_level = (FileLoadLevel)level; if (success) - m_pDomainAssembly->SetLoadLevel(level); + m_pAssembly->SetLoadLevel(level); } #ifndef DACCESS_COMPILE @@ -2046,7 +2046,7 @@ BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success) case FILE_LOAD_DELIVER_EVENTS: case FILE_LOADED: case FILE_ACTIVE: // The timing of stress logs is not critical, so even for the FILE_ACTIVE stage we need not do it while the m_pList lock is held. - STRESS_LOG3(LF_CLASSLOADER, LL_INFO100, "Completed Load Level %s for DomainAssembly %p - success = %i\n", fileLoadLevelName[level], m_pDomainAssembly, success); + STRESS_LOG3(LF_CLASSLOADER, LL_INFO100, "Completed Load Level %s for Assembly %p - success = %i\n", fileLoadLevelName[level], m_pAssembly, success); break; default: break; @@ -2075,9 +2075,9 @@ void FileLoadLock::SetError(Exception *ex) m_cachedHR = ex->GetHR(); LOG((LF_LOADER, LL_WARNING, "LOADER: ***%s*\t!!!Non-transient error 0x%x\n", - m_pDomainAssembly->GetSimpleName(), m_cachedHR)); + m_pAssembly->GetSimpleName(), m_cachedHR)); - m_pDomainAssembly->SetError(ex); + m_pAssembly->SetError(ex); CompleteLoadLevel(FILE_ACTIVE, FALSE); } @@ -2105,10 +2105,10 @@ UINT32 FileLoadLock::Release() return count; } -FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEAssembly * pPEAssembly, DomainAssembly *pDomainAssembly) +FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEAssembly * pPEAssembly, Assembly *pAssembly) : ListLockEntry(pLock, pPEAssembly, "File load lock"), m_level((FileLoadLevel) (FILE_LOAD_CREATE)), - m_pDomainAssembly(pDomainAssembly), + m_pAssembly(pAssembly), m_cachedHR(S_OK) { WRAPPER_NO_CONTRACT; @@ -2172,21 +2172,21 @@ void AppDomain::LoadSystemAssemblies() // thread has completed the load step. // -BOOL AppDomain::IsLoading(DomainAssembly *pFile, FileLoadLevel level) +BOOL AppDomain::IsLoading(Assembly *pAssembly, FileLoadLevel level) { // Cheap out - if (pFile->GetLoadLevel() < level) + if (pAssembly->GetLoadLevel() < level) { FileLoadLock *pLock = NULL; { LoadLockHolder lock(this); - pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly()); + pLock = (FileLoadLock *) lock->FindFileLock(pAssembly->GetPEAssembly()); if (pLock == NULL) { // No thread involved with loading - return pFile->GetLoadLevel() >= level; + return pAssembly->GetLoadLevel() >= level; } pLock->AddRef(); @@ -2209,16 +2209,16 @@ BOOL AppDomain::IsLoading(DomainAssembly *pFile, FileLoadLevel level) // CheckLoading is a weaker form of IsLoading, which will not block on // other threads waiting for their status. This is appropriate for asserts. -CHECK AppDomain::CheckLoading(DomainAssembly *pFile, FileLoadLevel level) +CHECK AppDomain::CheckLoading(Assembly *pAssembly, FileLoadLevel level) { // Cheap out - if (pFile->GetLoadLevel() < level) + if (pAssembly->GetLoadLevel() < level) { FileLoadLock *pLock = NULL; LoadLockHolder lock(this); - pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly()); + pLock = (FileLoadLock *) lock->FindFileLock(pAssembly->GetPEAssembly()); if (pLock != NULL && pLock->CanAcquire(level)) @@ -2275,7 +2275,7 @@ CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD) #endif // !DACCESS_COMPILE -void AppDomain::LoadDomainAssembly(DomainAssembly *pFile, +void AppDomain::LoadAssembly(Assembly *pAssembly, FileLoadLevel targetLevel) { CONTRACTL @@ -2288,26 +2288,26 @@ void AppDomain::LoadDomainAssembly(DomainAssembly *pFile, CONTRACTL_END; // Quick exit if finished - if (pFile->GetLoadLevel() >= targetLevel) + if (pAssembly->GetLoadLevel() >= targetLevel) return; // Handle the error case - pFile->ThrowIfError(targetLevel); + pAssembly->ThrowIfError(targetLevel); #ifndef DACCESS_COMPILE - if (pFile->IsLoading()) + if (pAssembly->IsLoading()) { GCX_PREEMP(); // Load some more if appropriate LoadLockHolder lock(this); - FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly()); + FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pAssembly->GetPEAssembly()); if (pLockEntry == NULL) { - _ASSERTE (!pFile->IsLoading()); + _ASSERTE (!pAssembly->IsLoading()); return; } @@ -2315,7 +2315,7 @@ void AppDomain::LoadDomainAssembly(DomainAssembly *pFile, lock.Release(); - LoadDomainAssembly(pLockEntry, targetLevel); + LoadAssembly(pLockEntry, targetLevel); } #else // DACCESS_COMPILE @@ -2339,7 +2339,7 @@ namespace } } -Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity, +Assembly *AppDomain::LoadAssembly(AssemblySpec* pSpec, PEAssembly * pPEAssembly, FileLoadLevel targetLevel) { @@ -2349,33 +2349,21 @@ Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity, THROWS; MODE_ANY; PRECONDITION(CheckPointer(pPEAssembly)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case + POSTCONDITION(CheckPointer(RETVAL)); INJECT_FAULT(COMPlusThrowOM();); } CONTRACT_END; - DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pPEAssembly, targetLevel); - PREFIX_ASSUME(pAssembly != NULL); - - RETURN pAssembly->GetAssembly(); -} - -DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec, - PEAssembly * pPEAssembly, - FileLoadLevel targetLevel) -{ - STATIC_CONTRACT_THROWS; - if (pSpec == nullptr) { // skip caching, since we don't have anything to base it on - return LoadDomainAssemblyInternal(pSpec, pPEAssembly, targetLevel); + RETURN LoadAssemblyInternal(pSpec, pPEAssembly, targetLevel); } - DomainAssembly* pRetVal = NULL; + Assembly* pRetVal = NULL; EX_TRY { - pRetVal = LoadDomainAssemblyInternal(pSpec, pPEAssembly, targetLevel); + pRetVal = LoadAssemblyInternal(pSpec, pPEAssembly, targetLevel); } EX_HOOK { @@ -2415,15 +2403,15 @@ DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec, } EX_END_HOOK; - return pRetVal; + RETURN pRetVal; } -DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, +Assembly *AppDomain::LoadAssemblyInternal(AssemblySpec* pIdentity, PEAssembly * pPEAssembly, FileLoadLevel targetLevel) { - CONTRACT(DomainAssembly *) + CONTRACT(Assembly *) { GC_TRIGGERS; THROWS; @@ -2439,7 +2427,7 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, CONTRACT_END; - DomainAssembly * result; + Assembly * result; // Go into preemptive mode since this may take a while. GCX_PREEMP(); @@ -2479,7 +2467,7 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, { // We are the first one in - create the DomainAssembly registerNewAssembly = true; - fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly); + fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly->GetAssembly()); pDomainAssembly.SuppressRelease(); pamTracker->SuppressRelease(); @@ -2502,12 +2490,12 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, if (result == NULL) { - // We pass our ref on fileLock to LoadDomainAssembly to release. + // We pass our ref on fileLock to LoadAssembly to release. // Note that if we throw here, we will poison fileLock with an error condition, // so it will not be removed until app domain unload. So there is no need // to release our ref count. - result = (DomainAssembly *)LoadDomainAssembly(fileLock, targetLevel); + result = LoadAssembly(fileLock, targetLevel); } else { @@ -2529,19 +2517,19 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity, { AssemblySpec spec; spec.InitializeSpec(result->GetPEAssembly()); - GetAppDomain()->AddAssemblyToCache(&spec, result); + GetAppDomain()->AddAssemblyToCache(&spec, result->GetDomainAssembly()); } else { - GetAppDomain()->AddAssemblyToCache(pIdentity, result); + GetAppDomain()->AddAssemblyToCache(pIdentity, result->GetDomainAssembly()); } RETURN result; -} // AppDomain::LoadDomainAssembly +} // AppDomain::LoadAssembly -DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel) +Assembly *AppDomain::LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel) { - CONTRACT(DomainAssembly *) + CONTRACT(Assembly *) { STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pLock)); @@ -2552,7 +2540,7 @@ DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel } CONTRACT_END; - DomainAssembly *pFile = pLock->GetDomainAssembly(); + Assembly *pAssembly = pLock->GetAssembly(); // Make sure we release the lock on exit FileLoadLockRefHolder lockRef(pLock); @@ -2560,9 +2548,9 @@ DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel // Do a quick out check for the already loaded case. if (pLock->GetLoadLevel() >= targetLevel) { - pFile->ThrowIfError(targetLevel); + pAssembly->ThrowIfError(targetLevel); - RETURN pFile; + RETURN pAssembly; } // Initialize a loading queue. This will hold any loads which are triggered recursively but @@ -2583,7 +2571,7 @@ DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel immediateTargetLevel = limit.GetLoadLevel(); LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t>>>Load initiated, %s/%s\n", - pFile->GetSimpleName(), + pAssembly->GetSimpleName(), fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel])); // Now loop and do the load incrementally to the target level. @@ -2610,28 +2598,28 @@ DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel || workLevel == FILE_ACTIVE) ? LL_INFO10 : LL_INFO1000, "LOADER: %p:***%s*\t loading at level %s\n", - this, pFile->GetSimpleName(), fileLoadLevelName[workLevel])); + this, pAssembly->GetSimpleName(), fileLoadLevelName[workLevel])); - TryIncrementalLoad(pFile, workLevel, fileLock); + TryIncrementalLoad(pAssembly, workLevel, fileLock); } } if (pLock->GetLoadLevel() == immediateTargetLevel-1) { LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t<<GetSimpleName(), + pAssembly->GetSimpleName(), fileLoadLevelName[immediateTargetLevel-1])); } } LOG((LF_LOADER, LL_INFO100, "LOADER: ***%s*\t<<GetSimpleName(), + pAssembly->GetSimpleName(), fileLoadLevelName[pLock->GetLoadLevel()])); } // There may have been an error stored on the domain file by another thread, or from a previous load - pFile->ThrowIfError(targetLevel); + pAssembly->ThrowIfError(targetLevel); // There are two normal results from the above loop. // @@ -2649,13 +2637,11 @@ DomainAssembly *AppDomain::LoadDomainAssembly(FileLoadLock *pLock, FileLoadLevel // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly // specify the minimum load level acceptable and throw if not reached.) - pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1)); - - - RETURN pFile; + pAssembly->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1)); + RETURN pAssembly; } -void AppDomain::TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder) +void AppDomain::TryIncrementalLoad(Assembly *pAssembly, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder) { STANDARD_VM_CONTRACT; @@ -2667,7 +2653,7 @@ void AppDomain::TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLeve EX_TRY { // Do the work - BOOL success = pFile->DoIncrementalLoad(workLevel); + BOOL success = pAssembly->DoIncrementalLoad(workLevel); // Complete the level. if (pLoadLock->CompleteLoadLevel(workLevel, success) && @@ -2675,7 +2661,7 @@ void AppDomain::TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLeve { lockHolder.Release(); released = TRUE; - pFile->DeliverAsyncEvents(); + pAssembly->DeliverAsyncEvents(); }; } EX_HOOK @@ -2684,7 +2670,7 @@ void AppDomain::TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLeve //We will cache this error and wire this load to forever fail, // unless the exception is transient or the file is loaded OK but just cannot execute - if (!pEx->IsTransient() && !pFile->IsLoaded()) + if (!pEx->IsTransient() && !pAssembly->IsLoaded()) { if (released) { @@ -2705,7 +2691,7 @@ void AppDomain::TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLeve } if (!EEFileLoadException::CheckType(pEx)) - EEFileLoadException::Throw(pFile->GetPEAssembly(), pEx->GetHR(), pEx); + EEFileLoadException::Throw(pAssembly->GetPEAssembly(), pEx->GetHR(), pEx); } // Otherwise, we simply abort this load, and can retry later on. @@ -2764,7 +2750,7 @@ void AppDomain::SetupSharedStatics() SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString()); } -DomainAssembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyOptions options/* = FindAssemblyOptions_None*/) +Assembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyOptions options/* = FindAssemblyOptions_None*/) { CONTRACTL { @@ -2779,9 +2765,9 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyO if (pPEAssembly->HasHostAssembly()) { DomainAssembly * pDA = pPEAssembly->GetHostAssembly()->GetDomainAssembly(); - if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError()))) + if (pDA != nullptr && (pDA->GetAssembly()->IsLoaded() || (includeFailedToLoad && pDA->GetAssembly()->IsError()))) { - return pDA; + return pDA->GetAssembly(); } return nullptr; } @@ -2798,7 +2784,7 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyO if (pManifestFile && pManifestFile->Equals(pPEAssembly)) { - return pDomainAssembly.GetValue(); + return pDomainAssembly.GetValue()->GetAssembly(); } } return NULL; @@ -3596,7 +3582,7 @@ BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching) CollectibleAssemblyHolder pDomainAssembly; while (i.Next(pDomainAssembly.This())) { - result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) || + result = (pDomainAssembly->GetAssembly()->NotifyDebuggerLoad(flags, attaching) || result); } @@ -3619,7 +3605,7 @@ void AppDomain::NotifyDebuggerUnload() while (i.Next(pDomainAssembly.This())) { LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n")); - pDomainAssembly->NotifyDebuggerUnload(); + pDomainAssembly->GetAssembly()->NotifyDebuggerUnload(); } } #endif // DEBUGGING_SUPPORTED @@ -4077,7 +4063,8 @@ AppDomain::AssemblyIterator::Next_Unlocked( continue; } - if (pDomainAssembly->IsError()) + Assembly* pAssembly = pDomainAssembly->GetAssembly(); + if (pAssembly->IsError()) { if (m_assemblyIterationFlags & kIncludeFailedToLoad) { @@ -4090,7 +4077,7 @@ AppDomain::AssemblyIterator::Next_Unlocked( // First, reject DomainAssemblies whose load status is not to be included in // the enumeration - if (pDomainAssembly->IsAvailableToProfilers() && + if (pAssembly->IsAvailableToProfilers() && (m_assemblyIterationFlags & kIncludeAvailableToProfilers)) { // The assembly has reached the state at which we would notify profilers, @@ -4100,7 +4087,7 @@ AppDomain::AssemblyIterator::Next_Unlocked( // kIncludeAvailableToProfilers contains some loaded AND loading // assemblies. } - else if (pDomainAssembly->IsLoaded()) + else if (pAssembly->IsLoaded()) { // A loaded assembly if (!(m_assemblyIterationFlags & kIncludeLoaded)) @@ -4138,7 +4125,7 @@ AppDomain::AssemblyIterator::Next_Unlocked( // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief // window during collectible assembly creation. No thread should need to have a pointer // to the just allocated DomainAssembly at this stage.) - if (!pDomainAssembly->GetAssembly()->GetModule()->IsTenured()) + if (!pAssembly->GetModule()->IsTenured()) { continue; // reject } diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 7197f4827199a..4561d3b6517ce 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -305,15 +305,15 @@ typedef PEFileListLock::Holder PEFileListLockHolder; class FileLoadLock : public ListLockEntry { private: - FileLoadLevel m_level; - DomainAssembly *m_pDomainAssembly; - HRESULT m_cachedHR; + FileLoadLevel m_level; + Assembly* m_pAssembly; + HRESULT m_cachedHR; public: - static FileLoadLock *Create(PEFileListLock *pLock, PEAssembly *pPEAssembly, DomainAssembly *pDomainAssembly); + static FileLoadLock *Create(PEFileListLock *pLock, PEAssembly *pPEAssembly, Assembly *pAssembly); ~FileLoadLock(); - DomainAssembly *GetDomainAssembly(); + Assembly *GetAssembly(); FileLoadLevel GetLoadLevel(); // CanAcquire will return FALSE if Acquire will definitely not take the lock due @@ -340,7 +340,7 @@ class FileLoadLock : public ListLockEntry private: - FileLoadLock(PEFileListLock *pLock, PEAssembly *pPEAssembly, DomainAssembly *pDomainAssembly); + FileLoadLock(PEFileListLock *pLock, PEAssembly *pPEAssembly, Assembly *pAssembly); static void HolderLeave(FileLoadLock *pThis); @@ -1068,12 +1068,11 @@ class AppDomain final CHECK CheckCanLoadTypes(Assembly *pAssembly); CHECK CheckCanExecuteManagedCode(MethodDesc* pMD); - CHECK CheckLoading(DomainAssembly *pFile, FileLoadLevel level); + CHECK CheckLoading(Assembly *pFile, FileLoadLevel level); - BOOL IsLoading(DomainAssembly *pFile, FileLoadLevel level); + BOOL IsLoading(Assembly *pFile, FileLoadLevel level); - void LoadDomainAssembly(DomainAssembly *pFile, - FileLoadLevel targetLevel); + void LoadAssembly(Assembly *pFile, FileLoadLevel targetLevel); enum FindAssemblyOptions { @@ -1081,40 +1080,34 @@ class AppDomain final FindAssemblyOptions_IncludeFailedToLoad = 0x1 }; - DomainAssembly * FindAssembly(PEAssembly* pPEAssembly, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL); + Assembly * FindAssembly(PEAssembly* pPEAssembly, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL); Assembly *LoadAssembly(AssemblySpec* pIdentity, PEAssembly *pPEAssembly, FileLoadLevel targetLevel); - // this function does not provide caching, you must use LoadDomainAssembly + CHECK CheckValidModule(Module *pModule); + + void LoadSystemAssemblies(); + +private: + // this function does not provide caching, you must use LoadAssembly // unless the call is guaranteed to succeed or you don't need the caching // (e.g. if you will FailFast or tear down the AppDomain anyway) // The main point that you should not bypass caching if you might try to load the same file again, // resulting in multiple DomainAssembly objects that share the same PEAssembly for ngen image //which is violating our internal assumptions - DomainAssembly *LoadDomainAssemblyInternal( AssemblySpec* pIdentity, - PEAssembly *pPEAssembly, - FileLoadLevel targetLevel); - - DomainAssembly *LoadDomainAssembly( AssemblySpec* pIdentity, - PEAssembly *pPEAssembly, - FileLoadLevel targetLevel); - - - CHECK CheckValidModule(Module *pModule); + Assembly *LoadAssemblyInternal(AssemblySpec* pIdentity, + PEAssembly *pPEAssembly, + FileLoadLevel targetLevel); - // private: - void LoadSystemAssemblies(); - - DomainAssembly *LoadDomainAssembly(FileLoadLock *pLock, - FileLoadLevel targetLevel); + Assembly *LoadAssembly(FileLoadLock *pLock, FileLoadLevel targetLevel); - void TryIncrementalLoad(DomainAssembly *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder); + void TryIncrementalLoad(Assembly *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder); #ifndef DACCESS_COMPILE // needs AssemblySpec - +public: //**************************************************************************************** // Returns and Inserts assemblies into a lookup cache based on the binding information // in the AssemblySpec. There can be many AssemblySpecs to a single assembly. @@ -1124,10 +1117,12 @@ class AppDomain final return m_AssemblyCache.LookupAssembly(pSpec, fThrow); } +private: PEAssembly* FindCachedFile(AssemblySpec* pSpec, BOOL fThrow = TRUE); BOOL IsCached(AssemblySpec *pSpec); #endif // DACCESS_COMPILE +public: BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pPEAssembly); BOOL RemoveFileFromCache(PEAssembly *pPEAssembly); @@ -1137,8 +1132,7 @@ class AppDomain final BOOL AddExceptionToCache(AssemblySpec* pSpec, Exception *ex); void AddUnmanagedImageToCache(LPCWSTR libraryName, NATIVE_LIBRARY_HANDLE hMod); NATIVE_LIBRARY_HANDLE FindUnmanagedImageInCache(LPCWSTR libraryName); - //**************************************************************************************** - // + // Adds or removes an assembly to the domain. void AddAssembly(DomainAssembly * assem); void RemoveAssembly(DomainAssembly * pAsm); @@ -1380,7 +1374,7 @@ class AppDomain final private: void RaiseLoadingAssemblyEvent(Assembly* pAssembly); - friend class DomainAssembly; + friend class Assembly; private: BOOL RaiseUnhandledExceptionEvent(OBJECTREF *pThrowable, BOOL isTerminating); diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 0fe4bf8896384..bca764804c447 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -123,19 +123,24 @@ Assembly::Assembly(PEAssembly* pPEAssembly, DebuggerAssemblyControlFlags debugge , m_pModule(NULL) , m_pPEAssembly(clr::SafeAddRef(pPEAssembly)) , m_pFriendAssemblyDescriptor(NULL) - , m_isDynamic(false) -#ifdef FEATURE_COLLECTIBLE_TYPES - , m_isCollectible{pLoaderAllocator->IsCollectible()} -#endif - , m_pLoaderAllocator{pLoaderAllocator} #ifdef FEATURE_COMINTEROP , m_pITypeLib(NULL) -#endif // FEATURE_COMINTEROP -#ifdef FEATURE_COMINTEROP , m_InteropAttributeStatus(INTEROP_ATTRIBUTE_UNSET) +#endif + , m_pLoaderAllocator{pLoaderAllocator} +#ifdef FEATURE_COLLECTIBLE_TYPES + , m_isCollectible{pLoaderAllocator->IsCollectible() != FALSE} +#endif + , m_isDynamic(false) + , m_isLoading{true} + , m_isTerminated{false} + , m_level{FILE_LOAD_CREATE} + , m_notifyFlags{NOT_NOTIFIED} + , m_pError{NULL} +#ifdef _DEBUG + , m_bDisableActivationCheck{false} #endif , m_debuggerFlags(debuggerFlags) - , m_fTerminated(FALSE) , m_hExposedObject{} { CONTRACTL @@ -225,9 +230,18 @@ Assembly::~Assembly() if (m_pPEAssembly) { + // Remove association first. + if (m_level >= FILE_LOAD_BEGIN) + { + UnregisterFromHostAssembly(); + } + m_pPEAssembly->Release(); } + delete m_pError; + + #ifdef FEATURE_COMINTEROP if (m_pITypeLib != nullptr && m_pITypeLib != Assembly::InvalidTypeLib) { @@ -281,7 +295,7 @@ void Assembly::Terminate( BOOL signalProfiler ) STRESS_LOG1(LF_LOADER, LL_INFO100, "Assembly::Terminate (this = 0x%p)\n", reinterpret_cast(this)); - if (this->m_fTerminated) + if (m_isTerminated) return; if (m_pClassLoader != NULL) @@ -300,7 +314,7 @@ void Assembly::Terminate( BOOL signalProfiler ) } #endif // PROFILING_SUPPORTED - this->m_fTerminated = TRUE; + m_isTerminated = true; } Assembly * Assembly::Create( @@ -497,12 +511,12 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar // Finish loading process // would be REALLY nice to unify this with main loading loop - pDomainAssembly->Begin(); - pDomainAssembly->DeliverSyncEvents(); - pDomainAssembly->DeliverAsyncEvents(); - pDomainAssembly->FinishLoad(); - pDomainAssembly->ClearLoading(); - pDomainAssembly->m_level = FILE_ACTIVE; + pAssem->Begin(); + pAssem->DeliverSyncEvents(); + pAssem->DeliverAsyncEvents(); + pAssem->FinishLoad(); + pAssem->ClearLoading(); + pAssem->m_level = FILE_ACTIVE; } { @@ -1882,33 +1896,6 @@ void DECLSPEC_NORETURN Assembly::ThrowBadImageException(LPCUTF8 pszNameSpace, #endif // #ifndef DACCESS_COMPILE -#ifndef DACCESS_COMPILE -void Assembly::EnsureActive() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - GetDomainAssembly()->EnsureActive(); -} -#endif //!DACCESS_COMPILE - -CHECK Assembly::CheckActivated() -{ -#ifndef DACCESS_COMPILE - WRAPPER_NO_CONTRACT; - - CHECK(GetDomainAssembly()->CheckActivated()); -#endif - CHECK_OK; -} - - - #ifdef DACCESS_COMPILE void diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index c0b56d9cd21c2..441e1c828e202 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -29,7 +29,6 @@ class SystemDomain; class ClassLoader; class AssemblyNative; class AssemblySpec; -class Pending; class AllocMemTracker; class FriendAssemblyDescriptor; @@ -43,17 +42,123 @@ class FriendAssemblyDescriptor; // class Assembly { - friend class SystemDomain; friend class ClassLoader; friend class AssemblyNative; friend class AssemblySpec; - friend class NDirect; friend class ClrDataAccess; private: Assembly(PEAssembly *pPEAssembly, DebuggerAssemblyControlFlags debuggerFlags, LoaderAllocator* pLoaderAllocator); void Init(AllocMemTracker *pamTracker); +// Load state tracking +public: + // Return the File's load level. Note that this is the last level actually successfully completed. + // Note that this is subtly different than the FileLoadLock's level, which is the last level + // which was triggered (but potentially skipped if error or inappropriate.) + FileLoadLevel GetLoadLevel() { LIMITED_METHOD_DAC_CONTRACT; return m_level; } + + // Error means that a permanent load error has occurred. + bool IsError() + { + LIMITED_METHOD_DAC_CONTRACT; + DACCOP_IGNORE(FieldAccess, "No marshalling required"); + return m_pError != NULL; + } + + // Loading means that the load is still being tracked by a FileLoadLock. + bool IsLoading() { LIMITED_METHOD_CONTRACT; return m_isLoading; } + + // Loaded means that the file can be used passively. This includes loading types, reflection, + // and jitting. + bool IsLoaded() { LIMITED_METHOD_DAC_CONTRACT; return m_level >= FILE_LOAD_DELIVER_EVENTS; } + + // Active means that the file can be used actively. This includes code execution, static field + // access, and instance allocation. + bool IsActive() { LIMITED_METHOD_CONTRACT; return m_level >= FILE_ACTIVE; } + + // Checks if the load has reached the point where profilers may be notified + // about the file. It's important that IF a profiler is notified, THEN this returns + // TRUE, otherwise there can be profiler-attach races where the profiler doesn't see + // the file via either enumeration or notification. As a result, this begins + // returning TRUE just before the profiler is actually notified. See + // code:ProfilerFunctionEnum::Init#ProfilerEnumAssemblies + bool IsAvailableToProfilers() + { + LIMITED_METHOD_DAC_CONTRACT; + return IsProfilerNotified(); // despite the name, this function returns TRUE just before we notify the profiler + } + + BOOL DoIncrementalLoad(FileLoadLevel targetLevel); + + void ClearLoading() { LIMITED_METHOD_CONTRACT; m_isLoading = false; } + void SetLoadLevel(FileLoadLevel level) { LIMITED_METHOD_CONTRACT; m_level = level; } + + BOOL NotifyDebuggerLoad(int flags, BOOL attaching); + void NotifyDebuggerUnload(); + + // Ensure that an assembly has reached at least the IsActive state. Throw if not + void EnsureActive() + { + WRAPPER_NO_CONTRACT; + return EnsureLoadLevel(FILE_ACTIVE); + } + + // CheckActivated is appropriate for asserts that the assembly can be actively used. + // Note that this is slightly different from IsActive in that it deals with reentrancy cases properly. + CHECK CheckActivated(); + + // EnsureLoadLevel is a generic routine used to ensure that the file is not in a delay loaded + // state (unless it needs to be.) This should be used when a particular level of loading + // is required for an operation. Note that deadlocks are tolerated so the level may be one + void EnsureLoadLevel(FileLoadLevel targetLevel) DAC_EMPTY(); + + // RequireLoadLevel throws an exception if the domain file isn't loaded enough. Note + // that this is intolerant of deadlock related failures so is only really appropriate for + // checks inside the main loading loop. + void RequireLoadLevel(FileLoadLevel targetLevel) DAC_EMPTY(); + + // This should be used to permanently set the load to fail. Do not use with transient conditions + void SetError(Exception *ex); + + // Throws if a load error has occurred + void ThrowIfError(FileLoadLevel targetLevel) DAC_EMPTY(); + + // Checks that a load error has not occurred before the given level + CHECK CheckNoError(FileLoadLevel targetLevel) DAC_EMPTY_RET(CHECK::OK()); + +private: + friend class AppDomain; + friend class FileLoadLock; + +#ifndef DACCESS_COMPILE + void Begin(); + void BeforeTypeLoad(); + void EagerFixups(); + void VtableFixups(); + void DeliverSyncEvents(); + void DeliverAsyncEvents(); + void FinishLoad(); + void Activate(); + + void RegisterWithHostAssembly(); + void UnregisterFromHostAssembly(); +#endif + + void SetProfilerNotified() { LIMITED_METHOD_CONTRACT; m_notifyFlags |= PROFILER_NOTIFIED; } + void SetDebuggerNotified() { LIMITED_METHOD_CONTRACT; m_notifyFlags |= DEBUGGER_NOTIFIED; } + void SetShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; m_notifyFlags |= DEBUGGER_NEEDNOTIFICATION; } + + // IsNotified means that the profiler API notification has been delivered + bool IsProfilerNotified() { LIMITED_METHOD_CONTRACT; return (m_notifyFlags & PROFILER_NOTIFIED) == PROFILER_NOTIFIED; } + bool IsDebuggerNotified() { LIMITED_METHOD_CONTRACT; return (m_notifyFlags & DEBUGGER_NOTIFIED) == DEBUGGER_NOTIFIED; } + bool ShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; return (m_notifyFlags & DEBUGGER_NEEDNOTIFICATION) == DEBUGGER_NEEDNOTIFICATION; } + + // CheckLoadLevel is an assert predicate used to verify the load level of an assembly. + // deadlockOK indicates that the level is allowed to be one short if we are restricted + // by loader reentrancy. + CHECK CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockOK = TRUE) DAC_EMPTY_RET(CHECK::OK()); + public: void StartUnload(); void Terminate( BOOL signalProfiler = TRUE ); @@ -92,20 +197,6 @@ class Assembly return m_pClassLoader; } - //----------------------------------------------------------------------------------------- - // EnsureActive ensures that the assembly is properly prepped in the current app domain - // for active uses like code execution, static field access, and instance allocation - //----------------------------------------------------------------------------------------- -#ifndef DACCESS_COMPILE - VOID EnsureActive(); -#endif - - //----------------------------------------------------------------------------------------- - // CheckActivated is a check predicate which should be used in active use paths like code - // execution, static field access, and instance allocation - //----------------------------------------------------------------------------------------- - CHECK CheckActivated(); - PTR_LoaderAllocator GetLoaderAllocator() { LIMITED_METHOD_DAC_CONTRACT; return m_pLoaderAllocator; } #ifdef LOGGING @@ -264,8 +355,8 @@ class Assembly void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); #endif - FORCEINLINE BOOL IsDynamic() { LIMITED_METHOD_CONTRACT; return m_isDynamic; } - FORCEINLINE BOOL IsCollectible() { LIMITED_METHOD_DAC_CONTRACT; return m_isCollectible; } + FORCEINLINE bool IsDynamic() { LIMITED_METHOD_CONTRACT; return m_isDynamic; } + FORCEINLINE bool IsCollectible() { LIMITED_METHOD_DAC_CONTRACT; return m_isCollectible; } void AddType(Module* pModule, mdTypeDef cl); @@ -403,6 +494,7 @@ class Assembly #endif public: void UpdateCachedFriendAssemblyInfo(); + private: PTR_ClassLoader m_pClassLoader; // Single Loader @@ -412,21 +504,30 @@ class Assembly FriendAssemblyDescriptor *m_pFriendAssemblyDescriptor; - BOOL m_isDynamic; -#ifdef FEATURE_COLLECTIBLE_TYPES - BOOL m_isCollectible; -#endif // FEATURE_COLLECTIBLE_TYPES - PTR_LoaderAllocator m_pLoaderAllocator; - #ifdef FEATURE_COMINTEROP // If a TypeLib is ever required for this module, cache the pointer here. ITypeLib *m_pITypeLib; InteropAttributeStatus m_InteropAttributeStatus; #endif // FEATURE_COMINTEROP - DebuggerAssemblyControlFlags m_debuggerFlags; + PTR_LoaderAllocator m_pLoaderAllocator; +#ifdef FEATURE_COLLECTIBLE_TYPES + bool m_isCollectible; +#endif // FEATURE_COLLECTIBLE_TYPES + bool m_isDynamic; + + // Load state tracking + bool m_isLoading; + bool m_isTerminated; + FileLoadLevel m_level; + DWORD m_notifyFlags; + Exception* m_pError; - BOOL m_fTerminated; +#ifdef _DEBUG + bool m_bDisableActivationCheck; +#endif + + DebuggerAssemblyControlFlags m_debuggerFlags; LOADERHANDLE m_hExposedObject; }; diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index cad3829428c15..3ca0783d65349 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -170,8 +170,7 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma PEAssemblyHolder pPEAssembly(PEAssembly::Open(pAssembly->GetPEImage(), pAssembly)); bindOperation.SetResult(pPEAssembly.GetValue()); - DomainAssembly *pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED); - RETURN pDomainAssembly->GetAssembly(); + RETURN pCurDomain->LoadAssembly(&spec, pPEAssembly, FILE_LOADED); } extern "C" void QCALLTYPE AssemblyNative_LoadFromPath(INT_PTR ptrNativeAssemblyBinder, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly) diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp index 685aa71675762..38d58814cb69a 100644 --- a/src/coreclr/vm/assemblyspec.cpp +++ b/src/coreclr/vm/assemblyspec.cpp @@ -378,7 +378,7 @@ Assembly *AssemblySpec::LoadAssembly(FileLoadLevel targetLevel, BinderTracing::AssemblyBindOperation bindOperation(this); bindOperation.SetResult(domainAssembly->GetPEAssembly(), true /*cached*/); - pDomain->LoadDomainAssembly(domainAssembly, targetLevel); + pDomain->LoadAssembly(domainAssembly->GetAssembly(), targetLevel); RETURN domainAssembly->GetAssembly(); } @@ -838,8 +838,7 @@ BOOL AssemblySpecBindingCache::StoreAssembly(AssemblySpec *pSpec, DomainAssembly THROWS; GC_TRIGGERS; MODE_ANY; - POSTCONDITION(UnsafeContains(this, pSpec)); - POSTCONDITION(UnsafeVerifyLookupAssembly(this, pSpec, pAssembly)); + POSTCONDITION((!RETVAL) || (UnsafeContains(this, pSpec) && UnsafeVerifyLookupAssembly(this, pSpec, pAssembly))); INJECT_FAULT(COMPlusThrowOM();); } CONTRACT_END; diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 4d585435d6440..6cb715056d06f 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -2300,8 +2300,7 @@ Module::GetAssemblyIfLoaded( if ((pAssembly != NULL) && !IsGCThread() && !IsStackWalkerThread()) { _ASSERTE(::GetAppDomain() != NULL); - DomainAssembly * pDomainAssembly = pAssembly->GetDomainAssembly(); - if ((pDomainAssembly == NULL) || !pDomainAssembly->IsLoaded()) + if (!pAssembly->IsLoaded()) pAssembly = NULL; } @@ -2330,7 +2329,7 @@ Module::GetAssemblyIfLoaded( DomainAssembly * pDomainAssembly = AppDomain::GetCurrentDomain()->FindCachedAssembly(&spec, FALSE /*fThrow*/); - if (pDomainAssembly && pDomainAssembly->IsLoaded()) + if (pDomainAssembly && pDomainAssembly->GetAssembly()->IsLoaded()) pAssembly = pDomainAssembly->GetAssembly(); // Only store in the rid map if working with the current AppDomain. @@ -2407,11 +2406,10 @@ Assembly * Module::LoadAssemblyImpl(mdAssemblyRef kAssemblyRef) Assembly * pAssembly = LookupAssemblyRef(kAssemblyRef); if (pAssembly != NULL) { - ::GetAppDomain()->LoadDomainAssembly(pAssembly->GetDomainAssembly(), FILE_LOADED); + ::GetAppDomain()->LoadAssembly(pAssembly, FILE_LOADED); RETURN pAssembly; } - DomainAssembly * pDomainAssembly; { PEAssemblyHolder pPEAssembly = GetPEAssembly()->LoadAssembly(kAssemblyRef); AssemblySpec spec; @@ -2424,14 +2422,13 @@ Assembly * Module::LoadAssemblyImpl(mdAssemblyRef kAssemblyRef) { spec.SetBinder(pBinder); } - pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED); + pAssembly = GetAppDomain()->LoadAssembly(&spec, pPEAssembly, FILE_LOADED); } - pAssembly = pDomainAssembly->GetAssembly(); - _ASSERTE(pDomainAssembly->IsLoaded() && pAssembly != NULL); + _ASSERTE(pAssembly != NULL && pAssembly->IsLoaded()); _ASSERTE( - pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find CoreLib (see AppDomain::FindCachedFile) - GetAssemblyIfLoaded(kAssemblyRef, NULL, pDomainAssembly->GetPEAssembly()->GetHostAssembly()->GetBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases + pAssembly->IsSystem() || // GetAssemblyIfLoaded will not find CoreLib (see AppDomain::FindCachedFile) + GetAssemblyIfLoaded(kAssemblyRef, NULL, pAssembly->GetPEAssembly()->GetHostAssembly()->GetBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases StoreAssemblyRef(kAssemblyRef, pAssembly); @@ -4458,7 +4455,7 @@ VOID Module::EnsureActive() MODE_ANY; } CONTRACTL_END; - GetDomainAssembly()->EnsureActive(); + GetAssembly()->EnsureActive(); } #endif // DACCESS_COMPILE @@ -4475,10 +4472,10 @@ CHECK Module::CheckActivated() CONTRACTL_END; #ifndef DACCESS_COMPILE - DomainAssembly *pDomainAssembly = GetDomainAssembly(); - CHECK(pDomainAssembly != NULL); - PREFIX_ASSUME(pDomainAssembly != NULL); - CHECK(pDomainAssembly->CheckActivated()); + Assembly *pAssembly = GetAssembly(); + CHECK(pAssembly != NULL); + PREFIX_ASSUME(pAssembly != NULL); + CHECK(pAssembly->CheckActivated()); #endif CHECK_OK; } diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index f41c21e2c7b8f..268b4a7164ad2 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -31,14 +31,7 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader , m_fCollectible(pLoaderAllocator->IsCollectible()) , m_NextDomainAssemblyInSameALC(NULL) , m_pLoaderAllocator(pLoaderAllocator) - , m_level(FILE_LOAD_CREATE) - , m_loading(TRUE) - , m_pError(NULL) - , m_bDisableActivationCheck(FALSE) - , m_fHostAssemblyPublished(FALSE) , m_debuggerFlags(DACF_NONE) - , m_notifyflags(NOT_NOTIFIED) - , m_fDebuggerUnloadStarted(FALSE) { CONTRACTL { @@ -79,14 +72,6 @@ DomainAssembly::~DomainAssembly() m_pPEAssembly->Release(); - delete m_pError; - - if (m_fHostAssemblyPublished) - { - // Remove association first. - UnregisterFromHostAssembly(); - } - if (m_pAssembly != NULL) { delete m_pAssembly; @@ -95,7 +80,7 @@ DomainAssembly::~DomainAssembly() // Optimization intended for EnsureLoadLevel only #include -void DomainAssembly::EnsureLoadLevel(FileLoadLevel targetLevel) +void Assembly::EnsureLoadLevel(FileLoadLevel targetLevel) { CONTRACT_VOID { @@ -108,7 +93,7 @@ void DomainAssembly::EnsureLoadLevel(FileLoadLevel targetLevel) TRIGGERSGC (); if (IsLoading()) { - AppDomain::GetCurrentDomain()->LoadDomainAssembly(this, targetLevel); + AppDomain::GetCurrentDomain()->LoadAssembly(this, targetLevel); // Enforce the loading requirement. Note that we may have a deadlock in which case we // may be off by one which is OK. (At this point if we are short of targetLevel we know @@ -123,7 +108,7 @@ void DomainAssembly::EnsureLoadLevel(FileLoadLevel targetLevel) } #include -CHECK DomainAssembly::CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockOK) +CHECK Assembly::CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockOK) { CONTRACTL { @@ -153,7 +138,7 @@ CHECK DomainAssembly::CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockO -void DomainAssembly::RequireLoadLevel(FileLoadLevel targetLevel) +void Assembly::RequireLoadLevel(FileLoadLevel targetLevel) { CONTRACT_VOID { @@ -173,7 +158,7 @@ void DomainAssembly::RequireLoadLevel(FileLoadLevel targetLevel) } -void DomainAssembly::SetError(Exception *ex) +void Assembly::SetError(Exception *ex) { CONTRACT_VOID { @@ -186,7 +171,7 @@ void DomainAssembly::SetError(Exception *ex) } CONTRACT_END; - m_pError = new ExInfo(ex->DomainBoundClone()); + m_pError = ex->DomainBoundClone(); if (m_pModule) { @@ -207,7 +192,7 @@ void DomainAssembly::SetError(Exception *ex) RETURN; } -void DomainAssembly::ThrowIfError(FileLoadLevel targetLevel) +void Assembly::ThrowIfError(FileLoadLevel targetLevel) { CONTRACT_VOID { @@ -218,16 +203,15 @@ void DomainAssembly::ThrowIfError(FileLoadLevel targetLevel) } CONTRACT_END; - if (m_level < targetLevel) + if (m_level < targetLevel && m_pError != NULL) { - if (m_pError) - m_pError->Throw(); + PAL_CPP_THROW(Exception*, m_pError->DomainBoundClone()); } RETURN; } -CHECK DomainAssembly::CheckNoError(FileLoadLevel targetLevel) +CHECK Assembly::CheckNoError(FileLoadLevel targetLevel) { LIMITED_METHOD_CONTRACT; CHECK(m_level >= targetLevel @@ -236,35 +220,7 @@ CHECK DomainAssembly::CheckNoError(FileLoadLevel targetLevel) CHECK_OK; } -CHECK DomainAssembly::CheckLoaded() -{ - CONTRACTL - { - INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - CHECK_MSG(CheckNoError(FILE_LOADED), "DomainAssembly load resulted in an error"); - - if (IsLoaded()) - CHECK_OK; - - // CoreLib is allowed to run managed code much earlier than other - // assemblies for bootstrapping purposes. This is because it has no - // dependencies, security checks, and doesn't rely on loader notifications. - - if (GetPEAssembly()->IsSystem()) - CHECK_OK; - - CHECK_MSG(GetPEAssembly()->IsLoaded(), "PEAssembly has not been loaded"); - - CHECK_OK; -} - -CHECK DomainAssembly::CheckActivated() +CHECK Assembly::CheckActivated() { CONTRACTL { @@ -275,7 +231,7 @@ CHECK DomainAssembly::CheckActivated() } CONTRACTL_END; - CHECK_MSG(CheckNoError(FILE_ACTIVE), "DomainAssembly load resulted in an error"); + CHECK_MSG(CheckNoError(FILE_ACTIVE), "Assembly load resulted in an error"); if (IsActive()) CHECK_OK; @@ -288,42 +244,24 @@ CHECK DomainAssembly::CheckActivated() CHECK_OK; CHECK_MSG(GetPEAssembly()->IsLoaded(), "PEAssembly has not been loaded"); - CHECK_MSG(IsLoaded(), "DomainAssembly has not been fully loaded"); + CHECK_MSG(IsLoaded(), "Assembly has not been fully loaded"); +#ifdef _DEBUG CHECK_MSG(m_bDisableActivationCheck || CheckLoadLevel(FILE_ACTIVE), "File has not had execution verified"); - +#endif CHECK_OK; } #endif //!DACCESS_COMPILE -// Return true iff the debugger should get notifications about this assembly. -// -// Notes: -// The debuggee may be stopped while a DomainAssmebly is being initialized. In this time window, -// GetAssembly() may be NULL. If that's the case, this function has to return FALSE. Later on, when -// the DomainAssembly is fully initialized, this function will return TRUE. This is the only scenario -// where this function is mutable. In other words, a DomainAssembly can only change from being invisible -// to visible, but NOT vice versa. Once a DomainAssmebly is fully initialized, this function should be -// immutable for an instance of a module. That ensures that the debugger gets consistent -// notifications about it. It this value mutates, than the debugger may miss relevant notifications. -BOOL DomainAssembly::IsVisibleToDebugger() -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return (GetAssembly() != NULL); -} - #ifndef DACCESS_COMPILE -BOOL DomainAssembly::DoIncrementalLoad(FileLoadLevel level) +BOOL Assembly::DoIncrementalLoad(FileLoadLevel level) { STANDARD_VM_CONTRACT; if (IsError()) return FALSE; - Thread *pThread = GetThread(); switch (level) { case FILE_LOAD_BEGIN: @@ -372,7 +310,7 @@ BOOL DomainAssembly::DoIncrementalLoad(FileLoadLevel level) return TRUE; } -void DomainAssembly::BeforeTypeLoad() +void Assembly::BeforeTypeLoad() { CONTRACTL { @@ -408,7 +346,7 @@ void DomainAssembly::BeforeTypeLoad() #endif } -void DomainAssembly::EagerFixups() +void Assembly::EagerFixups() { WRAPPER_NO_CONTRACT; @@ -421,14 +359,14 @@ void DomainAssembly::EagerFixups() #endif // FEATURE_READYTORUN } -void DomainAssembly::VtableFixups() +void Assembly::VtableFixups() { WRAPPER_NO_CONTRACT; GetModule()->FixupVTables(); } -void DomainAssembly::FinishLoad() +void Assembly::FinishLoad() { CONTRACTL { @@ -444,7 +382,7 @@ void DomainAssembly::FinishLoad() DACNotify::DoModuleLoadNotification(m_pModule); } -void DomainAssembly::Activate() +void Assembly::Activate() { CONTRACT_VOID { @@ -457,7 +395,6 @@ void DomainAssembly::Activate() // We cannot execute any code in this assembly until we know what exception plan it is on. // At the point of an exception's stack-crawl it is too late because we cannot tolerate a GC. // See PossiblyUnwrapThrowable and its callers. - _ASSERTE(GetModule() == GetAssembly()->GetModule()); GetModule()->IsRuntimeWrapExceptions(); // @@ -469,7 +406,9 @@ void DomainAssembly::Activate() if (pMT != NULL) { pMT->CheckRestore(); +#ifdef _DEBUG m_bDisableActivationCheck=TRUE; +#endif pMT->CheckRunClassInitThrowing(); } #ifdef _DEBUG @@ -489,20 +428,19 @@ void DomainAssembly::Activate() RETURN; } -void DomainAssembly::Begin() +void Assembly::Begin() { STANDARD_VM_CONTRACT; { AppDomain::LoadLockHolder lock(AppDomain::GetCurrentDomain()); - AppDomain::GetCurrentDomain()->AddAssembly(this); + AppDomain::GetCurrentDomain()->AddAssembly(GetDomainAssembly()); } // Make it possible to find this DomainAssembly object from associated BINDER_SPACE::Assembly. RegisterWithHostAssembly(); - m_fHostAssemblyPublished = true; } -void DomainAssembly::RegisterWithHostAssembly() +void Assembly::RegisterWithHostAssembly() { CONTRACTL { @@ -514,11 +452,11 @@ void DomainAssembly::RegisterWithHostAssembly() if (GetPEAssembly()->HasHostAssembly()) { - GetPEAssembly()->GetHostAssembly()->SetDomainAssembly(this); + GetPEAssembly()->GetHostAssembly()->SetDomainAssembly(GetDomainAssembly()); } } -void DomainAssembly::UnregisterFromHostAssembly() +void Assembly::UnregisterFromHostAssembly() { CONTRACTL { @@ -534,7 +472,7 @@ void DomainAssembly::UnregisterFromHostAssembly() } } -void DomainAssembly::DeliverAsyncEvents() +void Assembly::DeliverAsyncEvents() { CONTRACTL { @@ -546,10 +484,10 @@ void DomainAssembly::DeliverAsyncEvents() CONTRACTL_END; OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE); - AppDomain::GetCurrentDomain()->RaiseLoadingAssemblyEvent(GetAssembly()); + AppDomain::GetCurrentDomain()->RaiseLoadingAssemblyEvent(this); } -void DomainAssembly::DeliverSyncEvents() +void Assembly::DeliverSyncEvents() { CONTRACTL { @@ -707,15 +645,12 @@ HRESULT DomainAssembly::GetDebuggingCustomAttributes(DWORD *pdwFlags) return hr; } -BOOL DomainAssembly::NotifyDebuggerLoad(int flags, BOOL attaching) +BOOL Assembly::NotifyDebuggerLoad(int flags, BOOL attaching) { WRAPPER_NO_CONTRACT; BOOL result = FALSE; - if (!IsVisibleToDebugger()) - return FALSE; - // Debugger Attach is done totally out-of-process. Does not call code in-proc. _ASSERTE(!attaching); @@ -731,7 +666,7 @@ BOOL DomainAssembly::NotifyDebuggerLoad(int flags, BOOL attaching) { if (ShouldNotifyDebugger()) { - g_pDebugInterface->LoadAssembly(this); + g_pDebugInterface->LoadAssembly(GetDomainAssembly()); } result = TRUE; } @@ -739,35 +674,30 @@ BOOL DomainAssembly::NotifyDebuggerLoad(int flags, BOOL attaching) if(this->ShouldNotifyDebugger()) { result = result || - this->GetModule()->NotifyDebuggerLoad(AppDomain::GetCurrentDomain(), this, flags, attaching); + this->GetModule()->NotifyDebuggerLoad(AppDomain::GetCurrentDomain(), GetDomainAssembly(), flags, attaching); } if( ShouldNotifyDebugger()) { - result|=m_pModule->NotifyDebuggerLoad(AppDomain::GetCurrentDomain(), this, ATTACH_MODULE_LOAD, attaching); + result|=m_pModule->NotifyDebuggerLoad(AppDomain::GetCurrentDomain(), GetDomainAssembly(), ATTACH_MODULE_LOAD, attaching); SetDebuggerNotified(); } return result; } -void DomainAssembly::NotifyDebuggerUnload() +void Assembly::NotifyDebuggerUnload() { LIMITED_METHOD_CONTRACT; - if (!IsVisibleToDebugger()) - return; - if (!AppDomain::GetCurrentDomain()->IsDebuggerAttached()) return; - m_fDebuggerUnloadStarted = TRUE; - // Dispatch module unload for the module. Debugger is resilient in case we haven't dispatched // a previous load event (such as if debugger attached after the modules was loaded). this->GetModule()->NotifyDebuggerUnload(AppDomain::GetCurrentDomain()); - g_pDebugInterface->UnloadAssembly(this); + g_pDebugInterface->UnloadAssembly(GetDomainAssembly()); } #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/domainassembly.h b/src/coreclr/vm/domainassembly.h index 3c9d6d0e6a93c..8ae63bff9f7b4 100644 --- a/src/coreclr/vm/domainassembly.h +++ b/src/coreclr/vm/domainassembly.h @@ -78,7 +78,6 @@ class DomainAssembly final Assembly* GetAssembly() { LIMITED_METHOD_DAC_CONTRACT; - CONSISTENCY_CHECK(CheckLoaded()); return m_pAssembly; } @@ -86,23 +85,10 @@ class DomainAssembly final Module* GetModule() { LIMITED_METHOD_CONTRACT; - CONSISTENCY_CHECK(CheckLoaded()); return m_pModule; } - IMDInternalImport *GetMDImport() - { - WRAPPER_NO_CONTRACT; - return m_pPEAssembly->GetMDImport(); - } - - BOOL IsSystem() - { - WRAPPER_NO_CONTRACT; - return GetPEAssembly()->IsSystem(); - } - LPCUTF8 GetSimpleName() { WRAPPER_NO_CONTRACT; @@ -123,94 +109,6 @@ class DomainAssembly final return m_fCollectible; } - // ------------------------------------------------------------ - // Loading state checks - // ------------------------------------------------------------ - - // Return the File's load level. Note that this is the last level actually successfully completed. - // Note that this is subtly different than the FileLoadLock's level, which is the last level - // which was triggered (but potentially skipped if error or inappropriate.) - FileLoadLevel GetLoadLevel() { LIMITED_METHOD_DAC_CONTRACT; return m_level; } - - // Error means that a permanent x-appdomain load error has occurred. - BOOL IsError() - { - LIMITED_METHOD_DAC_CONTRACT; - DACCOP_IGNORE(FieldAccess, "No marshalling required"); - return m_pError != NULL; - } - - // Loading means that the load is still being tracked by a FileLoadLock. - BOOL IsLoading() { LIMITED_METHOD_CONTRACT; return m_loading; } - - // Loaded means that the file can be used passively. This includes loading types, reflection, and - // jitting. - BOOL IsLoaded() { LIMITED_METHOD_DAC_CONTRACT; return m_level >= FILE_LOAD_DELIVER_EVENTS; } - - // Active means that the file can be used actively in the current app domain. Note that a shared file - // may conditionally not be able to be made active on a per app domain basis. - BOOL IsActive() { LIMITED_METHOD_CONTRACT; return m_level >= FILE_ACTIVE; } - - // Checks if the load has reached the point where profilers may be notified - // about the file. It's important that IF a profiler is notified, THEN this returns - // TRUE, otherwise there can be profiler-attach races where the profiler doesn't see - // the file via either enumeration or notification. As a result, this begins - // returning TRUE just before the profiler is actually notified. See - // code:ProfilerFunctionEnum::Init#ProfilerEnumAssemblies - BOOL IsAvailableToProfilers() - { - LIMITED_METHOD_DAC_CONTRACT; - return IsProfilerNotified(); // despite the name, this function returns TRUE just before we notify the profiler - } - - // CheckLoaded is appropriate for asserts that the assembly can be passively used. - CHECK CheckLoaded(); - - // CheckActivated is appropriate for asserts that the assembly can be actively used. Note that - // it is slightly different from IsActive in that it deals with reentrancy cases properly. - CHECK CheckActivated(); - - // Ensure that an assembly has reached at least the IsLoaded state. Throw if not. - void EnsureLoaded() - { - WRAPPER_NO_CONTRACT; - return EnsureLoadLevel(FILE_LOADED); - } - - // Ensure that an assembly has reached at least the IsActive state. Throw if not. - void EnsureActive() - { - WRAPPER_NO_CONTRACT; - return EnsureLoadLevel(FILE_ACTIVE); - } - - // EnsureLoadLevel is a generic routine used to ensure that the file is not in a delay loaded - // state (unless it needs to be.) This should be used when a particular level of loading - // is required for an operation. Note that deadlocks are tolerated so the level may be one - void EnsureLoadLevel(FileLoadLevel targetLevel) DAC_EMPTY(); - - // CheckLoadLevel is an assert predicate used to verify the load level of an assembly. - // deadlockOK indicates that the level is allowed to be one short if we are restricted - // by loader reentrancy. - CHECK CheckLoadLevel(FileLoadLevel requiredLevel, BOOL deadlockOK = TRUE) DAC_EMPTY_RET(CHECK::OK()); - - // RequireLoadLevel throws an exception if the domain file isn't loaded enough. Note - // that this is intolerant of deadlock related failures so is only really appropriate for - // checks inside the main loading loop. - void RequireLoadLevel(FileLoadLevel targetLevel) DAC_EMPTY(); - - // Throws if a load error has occurred - void ThrowIfError(FileLoadLevel targetLevel) DAC_EMPTY(); - - // Checks that a load error has not occurred before the given level - CHECK CheckNoError(FileLoadLevel targetLevel) DAC_EMPTY_RET(CHECK::OK()); - - // IsNotified means that the profiler API notification has been delivered - BOOL IsProfilerNotified() { LIMITED_METHOD_CONTRACT; return m_notifyflags & PROFILER_NOTIFIED; } - BOOL IsDebuggerNotified() { LIMITED_METHOD_CONTRACT; return m_notifyflags & DEBUGGER_NOTIFIED; } - BOOL ShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; return m_notifyflags & DEBUGGER_NEEDNOTIFICATION; } - - // ------------------------------------------------------------ // Other public APIs // ------------------------------------------------------------ @@ -248,85 +146,9 @@ class DomainAssembly final friend class AppDomain; friend class Assembly; - friend class Module; - friend class FileLoadLock; DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator, AllocMemTracker* memTracker); - BOOL DoIncrementalLoad(FileLoadLevel targetLevel); - void ClearLoading() { LIMITED_METHOD_CONTRACT; m_loading = FALSE; } - void SetLoadLevel(FileLoadLevel level) { LIMITED_METHOD_CONTRACT; m_level = level; } - -#ifndef DACCESS_COMPILE - void Begin(); - void BeforeTypeLoad(); - void EagerFixups(); - void VtableFixups(); - void DeliverSyncEvents(); - void DeliverAsyncEvents(); - void FinishLoad(); - void Activate(); - - void RegisterWithHostAssembly(); - void UnregisterFromHostAssembly(); -#endif - - // This should be used to permanently set the load to fail. Do not use with transient conditions - void SetError(Exception *ex); - - void SetProfilerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|= PROFILER_NOTIFIED; } - void SetDebuggerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NOTIFIED; } - void SetShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NEEDNOTIFICATION; } - - class ExInfo - { - enum - { - ExType_ClrEx, - ExType_HR - } - m_type; - union - { - Exception* m_pEx; - HRESULT m_hr; - }; - - public: - void Throw() - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - if (m_type == ExType_ClrEx) - { - PAL_CPP_THROW(Exception*, m_pEx->DomainBoundClone()); - } - if (m_type == ExType_HR) - ThrowHR(m_hr); - _ASSERTE(!"Bad exception type"); - ThrowHR(E_UNEXPECTED); - }; - - ExInfo(Exception* pEx) - { - LIMITED_METHOD_CONTRACT; - m_type = ExType_ClrEx; - m_pEx = pEx; - }; - - ~ExInfo() - { - LIMITED_METHOD_CONTRACT; - if (m_type == ExType_ClrEx) - delete m_pEx; - } - }; - public: // ------------------------------------------------------------ // Debugger control API @@ -349,10 +171,6 @@ class DomainAssembly final HRESULT GetDebuggingCustomAttributes(DWORD* pdwFlags); - BOOL IsVisibleToDebugger(); - BOOL NotifyDebuggerLoad(int flags, BOOL attaching); - void NotifyDebuggerUnload(); - private: // ------------------------------------------------------------ // Instance data @@ -366,17 +184,7 @@ class DomainAssembly final DomainAssembly* m_NextDomainAssemblyInSameALC; PTR_LoaderAllocator m_pLoaderAllocator; - FileLoadLevel m_level; - BOOL m_loading; - - ExInfo* m_pError; - - BOOL m_bDisableActivationCheck; - BOOL m_fHostAssemblyPublished; - DebuggerAssemblyControlFlags m_debuggerFlags; - DWORD m_notifyflags; - BOOL m_fDebuggerUnloadStarted; }; #endif // _DOMAINASSEMBLY_H_ diff --git a/src/coreclr/vm/eventtrace_bulktype.cpp b/src/coreclr/vm/eventtrace_bulktype.cpp index 934bb14fd7fea..a2d30fa1ca487 100644 --- a/src/coreclr/vm/eventtrace_bulktype.cpp +++ b/src/coreclr/vm/eventtrace_bulktype.cpp @@ -517,10 +517,10 @@ void BulkStaticsLogger::LogAllStatics() while (assemblyIter.Next(pDomainAssembly.This())) { // Make sure the assembly is loaded. - if (!pDomainAssembly->IsLoaded()) + CollectibleAssemblyHolder pAssembly = pDomainAssembly->GetAssembly(); + if (!pAssembly->IsLoaded()) continue; - CollectibleAssemblyHolder pAssembly = pDomainAssembly->GetAssembly(); // Get the domain module from the module/appdomain pair. Module *module = pDomainAssembly->GetModule(); if (module == NULL) @@ -531,7 +531,7 @@ void BulkStaticsLogger::LogAllStatics() continue; // Ensure the module has fully loaded. - if (!domainAssembly->IsActive()) + if (!pAssembly->IsActive()) continue; // Now iterate all types with diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index dde9db0f76a00..dc1f4d72d00b9 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -542,7 +542,7 @@ void LoaderAllocator::GCLoaderAllocators(LoaderAllocator* pOriginalLoaderAllocat // Call AssemblyUnloadStarted event domainAssemblyIt->GetAssembly()->StartUnload(); // Notify the debugger - domainAssemblyIt->NotifyDebuggerUnload(); + domainAssemblyIt->GetAssembly()->NotifyDebuggerUnload(); domainAssemblyIt++; } diff --git a/src/coreclr/vm/multicorejit.cpp b/src/coreclr/vm/multicorejit.cpp index 611a32543e71f..bac039f9d0908 100644 --- a/src/coreclr/vm/multicorejit.cpp +++ b/src/coreclr/vm/multicorejit.cpp @@ -237,11 +237,11 @@ FileLoadLevel MulticoreJitManager::GetModuleFileLoadLevel(Module * pModule) if (pModule != NULL) { - DomainAssembly * pDomainAssembly = pModule->GetDomainAssembly(); + Assembly * pAssembly = pModule->GetAssembly(); - if (pDomainAssembly != NULL) + if (pAssembly != NULL) { - level = pDomainAssembly->GetLoadLevel(); + level = pAssembly->GetLoadLevel(); } } diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp index df387a828b0da..7613cdfd180d3 100644 --- a/src/coreclr/vm/peassembly.cpp +++ b/src/coreclr/vm/peassembly.cpp @@ -497,7 +497,7 @@ PEAssembly* PEAssembly::LoadAssembly(mdAssemblyRef kAssemblyRef) AssemblySpec spec; - spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(this)->GetAssembly()); + spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(this)); RETURN GetAppDomain()->BindAssemblySpec(&spec, TRUE); } @@ -538,8 +538,8 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, else { AppDomain* pAppDomain = AppDomain::GetCurrentDomain(); - DomainAssembly* pParentAssembly = pAppDomain->FindAssembly(this); - pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly->GetAssembly(), szName); + Assembly* pParentAssembly = pAppDomain->FindAssembly(this); + pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly, szName); if (pAssembly == NULL) return FALSE; pPEAssembly = pAssembly->GetPEAssembly(); diff --git a/src/coreclr/vm/profilingenumerators.cpp b/src/coreclr/vm/profilingenumerators.cpp index c55d40ffbeed9..b0741dcefe71f 100644 --- a/src/coreclr/vm/profilingenumerators.cpp +++ b/src/coreclr/vm/profilingenumerators.cpp @@ -491,8 +491,8 @@ HRESULT IterateAppDomainContainingModule::AddAppDomainContainingModule(AppDomain } CONTRACTL_END; - DomainAssembly * pDomainAssembly = m_pModule->GetDomainAssembly(); - if ((pDomainAssembly != NULL) && (pDomainAssembly->IsAvailableToProfilers())) + Assembly * pAssembly = m_pModule->GetAssembly(); + if ((pAssembly != NULL) && (pAssembly->IsAvailableToProfilers())) { if (m_index < m_cAppDomainIds) { diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index d4bb3f528b86e..d332fc12a468c 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -1282,7 +1282,7 @@ extern "C" BOOL QCALLTYPE RuntimeFieldHandle_GetRVAFieldInfo(FieldDesc* pField, Module* pModule = pField->GetModule(); *address = pModule->GetRvaField(pField->GetOffset()); *size = pField->LoadSize(); - + ret = TRUE; } @@ -1332,12 +1332,12 @@ extern "C" void QCALLTYPE ReflectionInvocation_RunModuleConstructor(QCall::Modul { QCALL_CONTRACT; - DomainAssembly *pDomainAssembly = pModule->GetDomainAssembly(); - if (pDomainAssembly != NULL && pDomainAssembly->IsActive()) + Assembly *pAssembly = pModule->GetAssembly(); + if (pAssembly != NULL && pAssembly->IsActive()) return; BEGIN_QCALL; - pDomainAssembly->EnsureActive(); + pAssembly->EnsureActive(); END_QCALL; } From ca00ae3726619ff129da50e9e10f56788cd07a98 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Thu, 12 Sep 2024 09:51:14 -0700 Subject: [PATCH 16/16] Work around F# ildasm/ilasm round-trip test failure (#107692) An F# compiler change caused significant generated IL change and an ildasm/ilasm round-trip test failure. Adding `false` reverts to the previous F# codegen and fixes the problem. Tracking: https://github.com/dotnet/runtime/issues/106601 --- src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj b/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj index 72ae06ccfc9b7..caabbe70689fe 100644 --- a/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj +++ b/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj @@ -8,6 +8,9 @@ true + + + false True