From dd88d29c022fae8805140b58cb4d44aa15e0d321 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:44:44 -0500 Subject: [PATCH 01/39] Fix init race in mono_class_try_get_[shortname]_class. (#112296) Backport of #112282 to release/9.0 We observed several crash reports in dotnet Android coming from google play store, like this one: https://github.com/dotnet/runtime/issues/109921#issuecomment-2640412870 and it happens at the following callstack: mono_class_setup_vtable_full at /__w/1/s/src/mono/mono/metadata/class-setup-vtable.c:900 init_io_stream_slots at /__w/1/s/src/mono/mono/metadata/icall.c:3378 ves_icall_System_IO_Stream_HasOverriddenBeginEndRead at /__w/1/s/src/mono/mono/metadata/icall.c:3437 (inlined by) ves_icall_System_IO_Stream_HasOverriddenBeginEndRead_raw at /__w/1/s/src/mono/mono/metadata/../metadata/icall-def.h:228 Looking a little deeper at that that code path expects call to mono_class_try_get_stream_class to succeed since it calls mono_class_setup_vtable on returned class pointer. There are other places where code expectes mono_class_try_get_[shortname]_class to always succeed or it will assert. Other locations handles the case where it returns NULL meaning that the class has been linked out. After looking into the macro implementation generating the mono_class_try_get_[shortname]_class functions it appears that it has a race where one thread could return NULL even if the class successfully gets loaded by another racing thread. Initially that might have been intentionally and callers would need to redo the call, but then there is no way for callers to distinct between hitting the race and class not available. Adding to the fact that code would also expect that some critical classes never fail loading, like what init_io_stream_slots does, this race ended up in race conditions. In the past, this particular race in init_io_stream_slots was hidden due to multiple calls to mono_class_try_get_stream_class minimzing the risk of a race to cause a crash. That implementation was however changed by https://github.com/dotnet/runtime/commit/e74da7c72c81787f8339df93cb6f13ac40b1e39d ending up in just one call to mono_class_try_get_stream_class in the critical paths. Since code relies on mono_class_try_get_[shortname]_class to succeed for some critical classes, code asserts if it returns NULL or crashes. The fix will use acquire/release semantics on the static variable guarding the cached type and make sure memory order is preserved on both read and write. Previous implementation adopted a similar approach but it took a copy of the static tmp_class into a local variable meaning that memory order would not be guaranteed, even if it applied memory barriers and volatile keywords on the static variables. Fix also adds an assert into init_io_stream_slots since it expects failures in calls to mono_class_try_get_stream_class as fatal. --- src/mono/mono/metadata/class-internals.h | 23 +++++++++-------------- src/mono/mono/metadata/icall.c | 2 ++ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index e44ba4c7b49026..55067f680d1b31 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -952,25 +952,20 @@ mono_class_get_##shortname##_class (void) \ // GENERATE_TRY_GET_CLASS_WITH_CACHE attempts mono_class_load_from_name approximately // only once. i.e. if it fails, it will return null and not retry. -// In a race it might try a few times, but not indefinitely. -// -// FIXME This maybe has excessive volatile/barriers. -// #define GENERATE_TRY_GET_CLASS_WITH_CACHE(shortname,name_space,name) \ MonoClass* \ mono_class_try_get_##shortname##_class (void) \ { \ - static volatile MonoClass *tmp_class; \ - static volatile gboolean inited; \ - MonoClass *klass = (MonoClass *)tmp_class; \ - mono_memory_barrier (); \ - if (!inited) { \ - klass = mono_class_try_load_from_name (mono_class_generate_get_corlib_impl (), name_space, name); \ - tmp_class = klass; \ - mono_memory_barrier (); \ - inited = TRUE; \ + static MonoClass *cached_class; \ + static gboolean cached_class_inited; \ + gboolean tmp_inited; \ + mono_atomic_load_acquire(tmp_inited, gboolean, &cached_class_inited); \ + if (G_LIKELY(tmp_inited)) { \ + return (MonoClass*)cached_class; \ } \ - return klass; \ + cached_class = mono_class_try_load_from_name (mono_class_generate_get_corlib_impl (), name_space, name); \ + mono_atomic_store_release(&cached_class_inited, TRUE); \ + return (MonoClass*)cached_class; \ } GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (safehandle) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 43f3d32653f321..e326e7a7b085a0 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -3391,6 +3391,8 @@ static void init_io_stream_slots (void) { MonoClass* klass = mono_class_try_get_stream_class (); + g_assert(klass); + mono_class_setup_vtable (klass); MonoMethod **klass_methods = m_class_get_methods (klass); if (!klass_methods) { From 19040ed3005d936a57450cf2858f1ac352c1199f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:46:55 -0500 Subject: [PATCH 02/39] Internal monitor impl not using coop mutex causing deadlocks on Android. (#112373) Backport of #112358 to release/9.0 On Android we have seen ANR issues, like the one described in https://github.com/dotnet/runtime/issues/111485. After investigating several different dumps including all threads it turns out that we could end up in a deadlock when init a monitor since that code path didn't use a coop mutex and owner of lock could end up in GC code while holding that lock, leading to deadlock if another thread was about to lock the same monitor init lock. In several dumps we see the following two threads: Thread 1: syscall+28 __futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+14 NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*)+384 sgen_gc_lock+105 mono_gc_wait_for_bridge_processing_internal+70 sgen_gchandle_get_target+288 alloc_mon+358 ves_icall_System_Threading_Monitor_Monitor_wait+452 ves_icall_System_Threading_Monitor_Monitor_wait_raw+583 Thread 2: syscall+28 __futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144 NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*)+652 alloc_mon+105 ves_icall_System_Threading_Monitor_Monitor_wait+452 ves_icall_System_Threading_Monitor_Monitor_wait_raw+583 So in this scenario Thread 1 holds monitor_mutex that is not a coop mutex and end up trying to take GC lock, since it calls, mono_gc_wait_for_bridge_processing_internal, but since a GC is already started (waiting on STW to complete), Thread 1 will block holding monitor_mutex. Thread 2 will try to lock monitor_mutex as well, and since its not a coop mutex it will block on OS __futex_wait_ex without changing Mono thread state to blocking, preventing the STW from processing. Fix is to switch to coop aware implementation of monitor_mutex. Normally this should have been resolved on Android since we run hybrid suspend meaning we should be able to run a signal handler on the blocking thread that would suspend it meaning that STW would continue, but for some reason the signal can't have been executed in this case putting the app under coop suspend limitations. This fix will take care of the deadlock, but if there are issues running Signals on Android, then threads not attached to runtime using coop attach methods could end up in similar situations blocking STW. Co-authored-by: lateralusX --- src/mono/mono/metadata/monitor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/metadata/monitor.c b/src/mono/mono/metadata/monitor.c index 6a72695e9fbedc..2e08f94d3361e7 100644 --- a/src/mono/mono/metadata/monitor.c +++ b/src/mono/mono/metadata/monitor.c @@ -82,9 +82,9 @@ struct _MonitorArray { MonoThreadsSync monitors [MONO_ZERO_LEN_ARRAY]; }; -#define mono_monitor_allocator_lock() mono_os_mutex_lock (&monitor_mutex) -#define mono_monitor_allocator_unlock() mono_os_mutex_unlock (&monitor_mutex) -static mono_mutex_t monitor_mutex; +#define mono_monitor_allocator_lock() mono_coop_mutex_lock (&monitor_mutex) +#define mono_monitor_allocator_unlock() mono_coop_mutex_unlock (&monitor_mutex) +static MonoCoopMutex monitor_mutex; static MonoThreadsSync *monitor_freelist; static MonitorArray *monitor_allocated; static int array_size = 16; @@ -255,7 +255,7 @@ lock_word_new_flat (gint32 owner) void mono_monitor_init (void) { - mono_os_mutex_init_recursive (&monitor_mutex); + mono_coop_mutex_init_recursive (&monitor_mutex); } static int From 0eef239a816a3c3d4295bab0f4d83515ddb2d2a8 Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Thu, 13 Feb 2025 08:31:01 +0000 Subject: [PATCH 03/39] [release/9.0-staging][iOS][globalization] Fix IndexOf on empty strings on iOS to return -1 (#112012) * Fix IndexOf on empty strings on iOS to return -1 * disable new test for hybrid glob on browser --- .../CompareInfo/CompareInfoTests.IndexOf.cs | 16 ++++++++++++--- .../System/StringTests.cs | 1 + .../pal_collation.m | 20 +++++++++++-------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.IndexOf.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.IndexOf.cs index ac39b82d74fb7c..6953eaafab818a 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.IndexOf.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.IndexOf.cs @@ -12,10 +12,20 @@ public class CompareInfoIndexOfTests : CompareInfoTestsBase { public static IEnumerable IndexOf_TestData() { - // Empty string + // Empty string, invariant yield return new object[] { s_invariantCompare, "foo", "", 0, 3, CompareOptions.None, 0, 0 }; yield return new object[] { s_invariantCompare, "foo", "", 2, 1, CompareOptions.None, 2, 0 }; yield return new object[] { s_invariantCompare, "", "", 0, 0, CompareOptions.None, 0, 0 }; + yield return new object[] { s_invariantCompare, "", "foo", 0, 0, CompareOptions.None, -1, 0 }; + + // Empty string, using non-invariant (s_germanCompare) CompareInfo to test the ICU path + yield return new object[] { s_germanCompare, "foo", "", 0, 3, CompareOptions.None, 0, 0 }; + yield return new object[] { s_germanCompare, "foo", "", 2, 1, CompareOptions.None, 2, 0 }; + yield return new object[] { s_germanCompare, "", "", 0, 0, CompareOptions.None, 0, 0 }; + if (!PlatformDetection.IsHybridGlobalizationOnBrowser) + { + yield return new object[] { s_germanCompare, "", "foo", 0, 0, CompareOptions.None, -1, 0 }; + } // OrdinalIgnoreCase yield return new object[] { s_invariantCompare, "Hello", "l", 0, 5, CompareOptions.OrdinalIgnoreCase, 2, 1 }; @@ -166,7 +176,7 @@ public static IEnumerable IndexOf_Aesc_Ligature_TestData() { bool useNls = PlatformDetection.IsNlsGlobalization; // Searches for the ligature \u00C6 - string source1 = "Is AE or ae the same as \u00C6 or \u00E6?"; // 3 failures here + string source1 = "Is AE or ae the same as \u00C6 or \u00E6?"; yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.None, useNls ? 24 : -1, useNls ? 1 : 0}; yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.None, 9 , 2}; yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.None, 24, 1 }; @@ -184,7 +194,7 @@ public static IEnumerable IndexOf_Aesc_Ligature_TestData() public static IEnumerable IndexOf_U_WithDiaeresis_TestData() { // Searches for the combining character sequence Latin capital letter U with diaeresis or Latin small letter u with diaeresis. - string source = "Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?"; // 7 failures here + string source = "Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?"; yield return new object[] { s_invariantCompare, source, "U\u0308", 8, 18, CompareOptions.None, 24, 1 }; yield return new object[] { s_invariantCompare, source, "u\u0308", 8, 18, CompareOptions.None, 9, 2 }; yield return new object[] { s_invariantCompare, source, "\u00DC", 8, 18, CompareOptions.None, 24, 1 }; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/StringTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/StringTests.cs index a6e16e2fce3caa..3355955051da9e 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/StringTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/StringTests.cs @@ -210,6 +210,7 @@ public static void Contains_Char(string s, char value, bool expected) [InlineData("Hello", 'e', StringComparison.CurrentCulture, true)] [InlineData("Hello", 'E', StringComparison.CurrentCulture, false)] [InlineData("", 'H', StringComparison.CurrentCulture, false)] + [InlineData("", '\u0301', StringComparison.CurrentCulture, false)] // Using non-ASCII character to test ICU path // CurrentCultureIgnoreCase [InlineData("Hello", 'H', StringComparison.CurrentCultureIgnoreCase, true)] [InlineData("Hello", 'Z', StringComparison.CurrentCultureIgnoreCase, false)] diff --git a/src/native/libs/System.Globalization.Native/pal_collation.m b/src/native/libs/System.Globalization.Native/pal_collation.m index ebe0db5c2c202a..56af941fb40033 100644 --- a/src/native/libs/System.Globalization.Native/pal_collation.m +++ b/src/native/libs/System.Globalization.Native/pal_collation.m @@ -117,6 +117,11 @@ int32_t GlobalizationNative_CompareStringNative(const uint16_t* localeName, int3 } } +/** + * Removes zero-width and other weightless characters such as U+200B (Zero Width Space), + * U+200C (Zero Width Non-Joiner), U+200D (Zero Width Joiner), U+FEFF (Zero Width No-Break Space), + * and the NUL character from the specified string. + */ static NSString* RemoveWeightlessCharacters(NSString* source) { NSError *error = nil; @@ -143,10 +148,9 @@ static int32_t IsIndexFound(int32_t fromBeginning, int32_t foundLocation, int32_ /* Function: IndexOf -Find detailed explanation how this function works in https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-hybrid-mode.md +Find detailed explanation how this function works in https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-hybrid-mode.md#string-indexing */ -Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpTarget, int32_t cwTargetLength, - const uint16_t* lpSource, int32_t cwSourceLength, int32_t comparisonOptions, int32_t fromBeginning) +Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpTarget, int32_t cwTargetLength, const uint16_t* lpSource, int32_t cwSourceLength, int32_t comparisonOptions, int32_t fromBeginning) { @autoreleasepool { @@ -158,6 +162,9 @@ Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNam return result; } NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions, true); + if (!fromBeginning) // LastIndexOf + options |= NSBackwardsSearch; + NSString *searchString = [NSString stringWithCharacters: lpTarget length: (NSUInteger)cwTargetLength]; NSString *searchStrCleaned = RemoveWeightlessCharacters(searchString); NSString *sourceString = [NSString stringWithCharacters: lpSource length: (NSUInteger)cwSourceLength]; @@ -168,7 +175,7 @@ Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNam searchStrCleaned = ConvertToKatakana(searchStrCleaned); } - if (sourceStrCleaned.length == 0 || searchStrCleaned.length == 0) + if (searchStrCleaned.length == 0) { result.location = fromBeginning ? 0 : (int32_t)sourceString.length; return result; @@ -178,9 +185,6 @@ Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNam NSString *searchStrPrecomposed = searchStrCleaned.precomposedStringWithCanonicalMapping; NSString *sourceStrPrecomposed = sourceStrCleaned.precomposedStringWithCanonicalMapping; - // last index - if (!fromBeginning) - options |= NSBackwardsSearch; // check if there is a possible match and return -1 if not // doesn't matter which normalization form is used here @@ -233,7 +237,7 @@ Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNam result.location = (int32_t)precomposedRange.location; result.length = (int32_t)precomposedRange.length; if (!(comparisonOptions & IgnoreCase)) - return result; + return result; } // check if sourceString has decomposed form of characters and searchString has precomposed form of characters From e08ac0ec158561c9779f6b67c667d3cbd90db93b Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Thu, 13 Feb 2025 10:24:59 +0100 Subject: [PATCH 04/39] Skip NegotiateStream_StreamToStream_Authentication_EmptyCredentials_Fails on WinSrv 2025 (#112473) --- .../TestUtilities/System/PlatformDetection.Windows.cs | 1 + .../FunctionalTests/NegotiateStreamStreamToStreamTest.cs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs index 6a166b298cd517..1cd57d147a77ed 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs @@ -26,6 +26,7 @@ public static partial class PlatformDetection public static bool IsWindows10OrLater => IsWindowsVersionOrLater(10, 0); public static bool IsWindowsServer2019 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 17763; public static bool IsWindowsServer2022 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 20348; + public static bool IsWindowsServer2025 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 26100; public static bool IsWindowsNanoServer => IsWindows && (IsNotWindowsIoTCore && GetWindowsInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase)); public static bool IsWindowsServerCore => IsWindows && GetWindowsInstallationType().Equals("Server Core", StringComparison.OrdinalIgnoreCase); public static int WindowsVersion => IsWindows ? (int)GetWindowsVersion() : -1; diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs index 7b8cc18c40f3b7..662f7d1fa48e93 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs @@ -9,8 +9,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; - +using Microsoft.DotNet.XUnitExtensions; using Xunit; +using Xunit.Abstractions; namespace System.Net.Security.Tests { @@ -192,6 +193,11 @@ public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials { string targetName = "testTargetName"; + if (PlatformDetection.IsWindowsServer2025) + { + throw new SkipTestException("Empty credentials not supported on Server 2025"); + } + // Ensure there is no confusion between DefaultCredentials / DefaultNetworkCredentials and a // NetworkCredential object with empty user, password and domain. NetworkCredential emptyNetworkCredential = new NetworkCredential("", "", ""); From 33a063585d61f314aa4197e7918a3f6a7967e1ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 16:44:07 -0800 Subject: [PATCH 05/39] [release/9.0-staging] Fix case-insensitive JSON deserialization of enum member names (#112057) * Fix case-insensitive deserialization of default enum values * renaming * Update comment --------- Co-authored-by: Pranav Senthilnathan --- .../Converters/Value/EnumConverter.cs | 27 ++++++++-- .../Serialization/EnumConverterTests.cs | 50 +++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs index 901cff255baa91..3fd753d7cb8cd3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs @@ -601,9 +601,9 @@ public void AppendConflictingField(EnumFieldInfo other) { Debug.Assert(JsonName.Equals(other.JsonName, StringComparison.OrdinalIgnoreCase), "The conflicting entry must be equal up to case insensitivity."); - if (Kind is EnumFieldNameKind.Default || JsonName.Equals(other.JsonName, StringComparison.Ordinal)) + if (ConflictsWith(this, other)) { - // Silently discard if the preceding entry is the default or has identical name. + // Silently discard if the new entry conflicts with the preceding entry return; } @@ -612,13 +612,34 @@ public void AppendConflictingField(EnumFieldInfo other) // Walk the existing list to ensure we do not add duplicates. foreach (EnumFieldInfo conflictingField in conflictingFields) { - if (conflictingField.Kind is EnumFieldNameKind.Default || conflictingField.JsonName.Equals(other.JsonName, StringComparison.Ordinal)) + if (ConflictsWith(conflictingField, other)) { return; } } conflictingFields.Add(other); + + // Determines whether the first field info matches everything that the second field info matches, + // in which case the second field info is redundant and doesn't need to be added to the list. + static bool ConflictsWith(EnumFieldInfo current, EnumFieldInfo other) + { + // The default name matches everything case-insensitively. + if (current.Kind is EnumFieldNameKind.Default) + { + return true; + } + + // current matches case-sensitively since it's not the default name. + // other matches case-insensitively, so it matches more than current. + if (other.Kind is EnumFieldNameKind.Default) + { + return false; + } + + // Both are case-sensitive so they need to be identical. + return current.JsonName.Equals(other.JsonName, StringComparison.Ordinal); + } } public EnumFieldInfo? GetMatchingField(ReadOnlySpan input) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs index 4668dbc6260f18..aecc33a26760b1 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/EnumConverterTests.cs @@ -1207,5 +1207,55 @@ public enum EnumWithInvalidMemberName6 [JsonStringEnumMemberName("Comma separators not allowed, in flags enums")] Value } + + [Theory] + [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseUpper)] + [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.SnakeCaseLower)] + [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseUpper)] + [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.KebabCaseLower)] + [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseUpper)] + [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.SnakeCaseLower)] + [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseUpper)] + [InlineData("\"pAsCaLcAsE\"", EnumWithVaryingNamingPolicies.PascalCase, JsonKnownNamingPolicy.KebabCaseLower)] + [InlineData("\"sNaKe_CaSe_UpPeR\"", EnumWithVaryingNamingPolicies.SNAKE_CASE_UPPER, JsonKnownNamingPolicy.SnakeCaseUpper)] + [InlineData("\"sNaKe_CaSe_LoWeR\"", EnumWithVaryingNamingPolicies.snake_case_lower, JsonKnownNamingPolicy.SnakeCaseLower)] + [InlineData("\"cAmElCaSe\"", EnumWithVaryingNamingPolicies.camelCase, JsonKnownNamingPolicy.CamelCase)] + [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.CamelCase)] + [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseUpper)] + [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.SnakeCaseLower)] + [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseUpper)] + [InlineData("\"a\"", EnumWithVaryingNamingPolicies.A, JsonKnownNamingPolicy.KebabCaseLower)] + [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.CamelCase)] + [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseUpper)] + [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.SnakeCaseLower)] + [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseUpper)] + [InlineData("\"B\"", EnumWithVaryingNamingPolicies.b, JsonKnownNamingPolicy.KebabCaseLower)] + public static void StringConverterWithNamingPolicyIsCaseInsensitive(string json, EnumWithVaryingNamingPolicies expectedValue, JsonKnownNamingPolicy namingPolicy) + { + JsonNamingPolicy policy = namingPolicy switch + { + JsonKnownNamingPolicy.CamelCase => JsonNamingPolicy.CamelCase, + JsonKnownNamingPolicy.SnakeCaseLower => JsonNamingPolicy.SnakeCaseLower, + JsonKnownNamingPolicy.SnakeCaseUpper => JsonNamingPolicy.SnakeCaseUpper, + JsonKnownNamingPolicy.KebabCaseLower => JsonNamingPolicy.KebabCaseLower, + JsonKnownNamingPolicy.KebabCaseUpper => JsonNamingPolicy.KebabCaseUpper, + _ => throw new ArgumentOutOfRangeException(nameof(namingPolicy)), + }; + + JsonSerializerOptions options = new() { Converters = { new JsonStringEnumConverter(policy) } }; + + EnumWithVaryingNamingPolicies value = JsonSerializer.Deserialize(json, options); + Assert.Equal(expectedValue, value); + } + + public enum EnumWithVaryingNamingPolicies + { + SNAKE_CASE_UPPER, + snake_case_lower, + camelCase, + PascalCase, + A, + b, + } } } From ec9ce26743b7edbd662fcbf95b7ee375954dbd33 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 08:55:05 -0800 Subject: [PATCH 06/39] [release/9.0-staging] Move generation of SuggestedBindingRedirects.targets to inner build (#112487) * Move generation of SuggestedBindingRedirects.targets to inner build These targets depend on the AssemblyVersion of the library which is specific to the inner-build of the library. Generate them in the inner-build. * Update src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj --------- Co-authored-by: Eric StJohn --- .../src/System.Resources.Extensions.csproj | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index e380af4d84271a..a178d029091157 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -9,7 +9,6 @@ false true $(BaseIntermediateOutputPath)SuggestedBindingRedirects.targets - $(BeforePack);GeneratePackageTargetsFile Provides classes which read and write resources in a format that supports non-primitive objects. Commonly Used Types: @@ -93,7 +92,8 @@ System.Resources.Extensions.PreserializedResourceWriter + AfterTargets="CoreCompile" + Condition="'$(TargetFramework)' == '$(NetFrameworkMinimum)'"> - <_RuntimeSymbolPath Include="$(RuntimeSymbolPath)" /> + <_RuntimeSymbolPath Include="@(TfmRuntimeSpecificPackageFile->'%(RootDir)%(Directory)%(FileName).pdb')" Condition="'%(TfmRuntimeSpecificPackageFile.Extension)' == '.dll'" KeepMetadata="None" /> Date: Wed, 26 Feb 2025 13:34:46 -0600 Subject: [PATCH 12/39] [release/9.0-staging] Add support for LDAPTLS_CACERTDIR \ TrustedCertificateDirectory (#112531) * Add support for LDAPTLS_CACERTDIR \ TrustedCertificateDirectory (#111877) * Add CompatibilitySuppressions.xml * Remove unwanted test changes that were ported from v10 --- .../Common/src/Interop/Interop.Ldap.cs | 2 + .../DirectoryServices/LDAP.Configuration.xml | 34 ++++---- .../ref/System.DirectoryServices.Protocols.cs | 4 + .../src/CompatibilitySuppressions.xml | 67 ++++++++++++++++ .../src/Resources/Strings.resx | 3 + .../Protocols/ldap/LdapConnection.cs | 4 +- .../ldap/LdapSessionOptions.Linux.cs | 49 ++++++++++++ .../ldap/LdapSessionOptions.Windows.cs | 10 +++ .../tests/DirectoryServicesProtocolsTests.cs | 77 +++++++++++++++++-- .../tests/LdapSessionOptionsTests.cs | 30 ++++++++ 10 files changed, 254 insertions(+), 26 deletions(-) create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs index 90c0ba997cd962..512242230093ff 100644 --- a/src/libraries/Common/src/Interop/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs @@ -157,6 +157,8 @@ internal enum LdapOption LDAP_OPT_ROOTDSE_CACHE = 0x9a, // Not Supported in Linux LDAP_OPT_DEBUG_LEVEL = 0x5001, LDAP_OPT_URI = 0x5006, // Not Supported in Windows + LDAP_OPT_X_TLS_CACERTDIR = 0x6003, // Not Supported in Windows + LDAP_OPT_X_TLS_NEWCTX = 0x600F, // Not Supported in Windows LDAP_OPT_X_SASL_REALM = 0x6101, LDAP_OPT_X_SASL_AUTHCID = 0x6102, LDAP_OPT_X_SASL_AUTHZID = 0x6103 diff --git a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml index 3523d7762232af..1a7f36e6f047bd 100644 --- a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml +++ b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml @@ -1,6 +1,6 @@ -To enable the tests marked with [ConditionalFact(nameof(IsLdapConfigurationExist))], you need to setup an LDAP server and provide the needed server info here. +To enable the tests marked with [ConditionalFact(nameof(IsLdapConfigurationExist))], you need to setup an LDAP server as described below and set the environment variable LDAP_TEST_SERVER_INDEX to the appropriate offset into the XML section found at the end of this file. To ship, we should test on both an Active Directory LDAP server, and at least one other server, as behaviors are a little different. However for local testing, it is easiest to connect to an OpenDJ LDAP server in a docker container (eg., in WSL2). @@ -11,7 +11,7 @@ OPENDJ SERVER test it with this command - it should return some results in WSL2 - ldapsearch -h localhost -p 1389 -D 'cn=admin,dc=example,dc=com' -x -w password + ldapsearch -H ldap://localhost:1389 -D 'cn=admin,dc=example,dc=com' -x -w password this command views the status @@ -24,16 +24,16 @@ SLAPD OPENLDAP SERVER and to test and view status - ldapsearch -h localhost -p 390 -D 'cn=admin,dc=example,dc=com' -x -w password + ldapsearch -H ldap://localhost:390 -D 'cn=admin,dc=example,dc=com' -x -w password docker exec -it slapd01 slapcat SLAPD OPENLDAP SERVER WITH TLS ============================== -The osixia/openldap container image automatically creates a TLS lisener with a self-signed certificate. This can be used to test TLS. +The osixia/openldap container image automatically creates a TLS listener with a self-signed certificate. This can be used to test TLS. -Start the container, with TLS on port 1636, without client certificate verification: +Start the container, with TLS on port 1636, but without client certificate verification: docker run --publish 1389:389 --publish 1636:636 --name ldap --hostname ldap.local --detach --rm --env LDAP_TLS_VERIFY_CLIENT=never --env LDAP_ADMIN_PASSWORD=password osixia/openldap --loglevel debug @@ -56,6 +56,8 @@ To test and view the status: ldapsearch -H ldaps://ldap.local:1636 -b dc=example,dc=org -x -D cn=admin,dc=example,dc=org -w password +use '-d 1' or '-d 2' for debugging. + ACTIVE DIRECTORY ================ @@ -65,7 +67,7 @@ When running against Active Directory from a Windows client, you should not see If you are running your AD server as a VM on the same machine that you are running WSL2, you must execute this command on the host to bridge the two Hyper-V networks so that it is visible from WSL2: - Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled + Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled The WSL2 VM should now be able to see the AD VM by IP address. To make it visible by host name, it's probably easiest to just add it to /etc/hosts. @@ -82,7 +84,7 @@ Note: @@ -105,15 +107,6 @@ Note: ServerBind,None False - - danmose-ldap.danmose-domain.com - DC=danmose-domain,DC=com - 389 - danmose-domain\Administrator - %TESTPASSWORD% - ServerBind,None - True - ldap.local DC=example,DC=org @@ -124,5 +117,14 @@ Note: true False + + danmose-ldap.danmose-domain.com + DC=danmose-domain,DC=com + 389 + danmose-domain\Administrator + %TESTPASSWORD% + ServerBind,None + True + diff --git a/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs b/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs index 32262da81be3e2..126be30b3ddb26 100644 --- a/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs +++ b/src/libraries/System.DirectoryServices.Protocols/ref/System.DirectoryServices.Protocols.cs @@ -382,6 +382,8 @@ public partial class LdapSessionOptions internal LdapSessionOptions() { } public bool AutoReconnect { get { throw null; } set { } } public string DomainName { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")] + public string TrustedCertificatesDirectory { get { throw null; } set { } } public string HostName { get { throw null; } set { } } public bool HostReachable { get { throw null; } } public System.DirectoryServices.Protocols.LocatorFlags LocatorFlag { get { throw null; } set { } } @@ -402,6 +404,8 @@ internal LdapSessionOptions() { } public bool Signing { get { throw null; } set { } } public System.DirectoryServices.Protocols.SecurityPackageContextConnectionInformation SslInformation { get { throw null; } } public int SspiFlag { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")] + public void StartNewTlsSessionContext() { } public bool TcpKeepAlive { get { throw null; } set { } } public System.DirectoryServices.Protocols.VerifyServerCertificateCallback VerifyServerCertificate { get { throw null; } set { } } public void FastConcurrentBind() { } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml b/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml new file mode 100644 index 00000000000000..2647f901c1a47e --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/CompatibilitySuppressions.xml @@ -0,0 +1,67 @@ + + + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/net8.0/System.DirectoryServices.Protocols.dll + lib/net8.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/net9.0/System.DirectoryServices.Protocols.dll + lib/net9.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.get_TrustedCertificatesDirectory + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.set_TrustedCertificatesDirectory(System.String) + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + + CP0002 + M:System.DirectoryServices.Protocols.LdapSessionOptions.StartNewTlsSessionContext + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + lib/netstandard2.0/System.DirectoryServices.Protocols.dll + true + + \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx b/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx index b63f103619fbdb..1f6c9734a7384c 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx +++ b/src/libraries/System.DirectoryServices.Protocols/src/Resources/Strings.resx @@ -426,4 +426,7 @@ Only ReferralChasingOptions.None and ReferralChasingOptions.All are supported on Linux. + + The directory '{0}' does not exist. + \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs index 1125bfd568d385..facdfc6a484bb9 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs @@ -955,13 +955,13 @@ private unsafe Interop.BOOL ProcessClientCertificate(IntPtr ldapHandle, IntPtr C private void Connect() { - //Ccurrently ldap does not accept more than one certificate. + // Currently ldap does not accept more than one certificate. if (ClientCertificates.Count > 1) { throw new InvalidOperationException(SR.InvalidClientCertificates); } - // Set the certificate callback routine here if user adds the certifcate to the certificate collection. + // Set the certificate callback routine here if user adds the certificate to the certificate collection. if (ClientCertificates.Count != 0) { int certError = LdapPal.SetClientCertOption(_ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _clientCertificateRoutine); diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs index e1cfffebb531fc..5059c40499d5c6 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.IO; +using System.Runtime.Versioning; namespace System.DirectoryServices.Protocols { @@ -11,6 +13,34 @@ public partial class LdapSessionOptions private bool _secureSocketLayer; + /// + /// Specifies the path of the directory containing CA certificates in the PEM format. + /// Multiple directories may be specified by separating with a semi-colon. + /// + /// + /// The certificate files are looked up by the CA subject name hash value where that hash can be + /// obtained by using, for example, openssl x509 -hash -noout -in CA.crt. + /// It is a common practice to have the certificate file be a symbolic link to the actual certificate file + /// which can be done by using openssl rehash . or c_rehash . in the directory + /// containing the certificate files. + /// + /// The directory not exist. + [UnsupportedOSPlatform("windows")] + public string TrustedCertificatesDirectory + { + get => GetStringValueHelper(LdapOption.LDAP_OPT_X_TLS_CACERTDIR, releasePtr: true); + + set + { + if (!Directory.Exists(value)) + { + throw new DirectoryNotFoundException(SR.Format(SR.DirectoryNotFound, value)); + } + + SetStringOptionHelper(LdapOption.LDAP_OPT_X_TLS_CACERTDIR, value); + } + } + public bool SecureSocketLayer { get @@ -52,6 +82,16 @@ public ReferralChasingOptions ReferralChasing } } + /// + /// Create a new TLS library context. + /// Calling this is necessary after setting TLS-based options, such as TrustedCertificatesDirectory. + /// + [UnsupportedOSPlatform("windows")] + public void StartNewTlsSessionContext() + { + SetIntValueHelper(LdapOption.LDAP_OPT_X_TLS_NEWCTX, 0); + } + private bool GetBoolValueHelper(LdapOption option) { if (_connection._disposed) throw new ObjectDisposedException(GetType().Name); @@ -71,5 +111,14 @@ private void SetBoolValueHelper(LdapOption option, bool value) ErrorChecking.CheckAndSetLdapError(error); } + + private void SetStringOptionHelper(LdapOption option, string value) + { + if (_connection._disposed) throw new ObjectDisposedException(GetType().Name); + + int error = LdapPal.SetStringOption(_connection._ldapHandle, option, value); + + ErrorChecking.CheckAndSetLdapError(error); + } } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs index 813005c5ecb72b..cc73449104adf4 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs @@ -10,6 +10,13 @@ public partial class LdapSessionOptions { private static void PALCertFreeCRLContext(IntPtr certPtr) => Interop.Ldap.CertFreeCRLContext(certPtr); + [UnsupportedOSPlatform("windows")] + public string TrustedCertificatesDirectory + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + public bool SecureSocketLayer { get @@ -24,6 +31,9 @@ public bool SecureSocketLayer } } + [UnsupportedOSPlatform("windows")] + public void StartNewTlsSessionContext() => throw new PlatformNotSupportedException(); + public int ProtocolVersion { get => GetIntValueHelper(LdapOption.LDAP_OPT_VERSION); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs index 00433bae9875c2..05dda66bbda001 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Diagnostics; using System.DirectoryServices.Tests; using System.Globalization; +using System.IO; using System.Net; -using System.Text; -using System.Threading; using Xunit; namespace System.DirectoryServices.Protocols.Tests @@ -16,6 +14,7 @@ public partial class DirectoryServicesProtocolsTests { internal static bool LdapConfigurationExists => LdapConfiguration.Configuration != null; internal static bool IsActiveDirectoryServer => LdapConfigurationExists && LdapConfiguration.Configuration.IsActiveDirectoryServer; + internal static bool UseTls => LdapConfigurationExists && LdapConfiguration.Configuration.UseTls; internal static bool IsServerSideSortSupported => LdapConfigurationExists && LdapConfiguration.Configuration.SupportsServerSideSort; @@ -706,6 +705,64 @@ public void TestMultipleServerBind() connection.Timeout = new TimeSpan(0, 3, 0); } +#if NET + [ConditionalFact(nameof(UseTls))] + [PlatformSpecific(TestPlatforms.Linux)] + public void StartNewTlsSessionContext() + { + using (var connection = GetConnection(bind: false)) + { + // We use "." as the directory since it must be a valid directory for StartNewTlsSessionContext() + Bind() to be successful even + // though there are no client certificates in ".". + connection.SessionOptions.TrustedCertificatesDirectory = "."; + + // For a real-world scenario, we would call 'StartTransportLayerSecurity(null)' here which would do the TLS handshake including + // providing the client certificate to the server and validating the server certificate. However, this requires additional + // setup that we don't have including trusting the server certificate and by specifying "demand" in the setup of the server + // via 'LDAP_TLS_VERIFY_CLIENT=demand' to force the TLS handshake to occur. + + connection.SessionOptions.StartNewTlsSessionContext(); + connection.Bind(); + + SearchRequest searchRequest = new (LdapConfiguration.Configuration.SearchDn, "(objectClass=*)", SearchScope.Subtree); + _ = (SearchResponse)connection.SendRequest(searchRequest); + } + } + + [ConditionalFact(nameof(UseTls))] + [PlatformSpecific(TestPlatforms.Linux)] + public void StartNewTlsSessionContext_ThrowsLdapException() + { + using (var connection = GetConnection(bind: false)) + { + // Create a new session context without setting TrustedCertificatesDirectory. + connection.SessionOptions.StartNewTlsSessionContext(); + Assert.Throws(() => connection.Bind()); + } + } + + [ConditionalFact(nameof(LdapConfigurationExists))] + [PlatformSpecific(TestPlatforms.Linux)] + public void TrustedCertificatesDirectory_ThrowsDirectoryNotFoundException() + { + using (var connection = GetConnection(bind: false)) + { + Assert.Throws(() => connection.SessionOptions.TrustedCertificatesDirectory = "nonexistent"); + } + } + + [ConditionalFact(nameof(LdapConfigurationExists))] + [PlatformSpecific(TestPlatforms.Windows)] + public void StartNewTlsSessionContext_ThrowsPlatformNotSupportedException() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Throws(() => options.StartNewTlsSessionContext()); + } + } +#endif + private void DeleteAttribute(LdapConnection connection, string entryDn, string attributeName) { string dn = entryDn + "," + LdapConfiguration.Configuration.SearchDn; @@ -786,24 +843,24 @@ private SearchResultEntry SearchUser(LdapConnection connection, string rootDn, s return null; } - private LdapConnection GetConnection(string server) + private static LdapConnection GetConnection(string server) { LdapDirectoryIdentifier directoryIdentifier = new LdapDirectoryIdentifier(server, fullyQualifiedDnsHostName: true, connectionless: false); return GetConnection(directoryIdentifier); } - private LdapConnection GetConnection() + private static LdapConnection GetConnection(bool bind = true) { LdapDirectoryIdentifier directoryIdentifier = string.IsNullOrEmpty(LdapConfiguration.Configuration.Port) ? new LdapDirectoryIdentifier(LdapConfiguration.Configuration.ServerName, fullyQualifiedDnsHostName: true, connectionless: false) : new LdapDirectoryIdentifier(LdapConfiguration.Configuration.ServerName, int.Parse(LdapConfiguration.Configuration.Port, NumberStyles.None, CultureInfo.InvariantCulture), fullyQualifiedDnsHostName: true, connectionless: false); - return GetConnection(directoryIdentifier); + return GetConnection(directoryIdentifier, bind); } - private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIdentifier) + private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIdentifier, bool bind = true) { NetworkCredential credential = new NetworkCredential(LdapConfiguration.Configuration.UserName, LdapConfiguration.Configuration.Password); @@ -816,7 +873,11 @@ private static LdapConnection GetConnection(LdapDirectoryIdentifier directoryIde // to LDAP v2, which we do not support, and will return LDAP_PROTOCOL_ERROR connection.SessionOptions.ProtocolVersion = 3; connection.SessionOptions.SecureSocketLayer = LdapConfiguration.Configuration.UseTls; - connection.Bind(); + + if (bind) + { + connection.Bind(); + } connection.Timeout = new TimeSpan(0, 3, 0); return connection; diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs index 5f6a737834ac23..2a8ab23a16d421 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs @@ -7,6 +7,8 @@ namespace System.DirectoryServices.Protocols.Tests { + // To enable these tests locally for Mono, comment out this line in DirectoryServicesTestHelpers.cs: + // [assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/35912", TestRuntimes.Mono)] [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class LdapSessionOptionsTests { @@ -27,6 +29,7 @@ public void ReferralChasing_Set_GetReturnsExpected_On_Windows(ReferralChasingOpt } [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/112146")] [PlatformSpecific(TestPlatforms.Linux)] [InlineData(ReferralChasingOptions.None)] [InlineData(ReferralChasingOptions.All)] @@ -756,5 +759,32 @@ public void StopTransportLayerSecurity_Disposed_ThrowsObjectDisposedException() Assert.Throws(() => connection.SessionOptions.StopTransportLayerSecurity()); } + +#if NET + [Fact] + [PlatformSpecific(TestPlatforms.Linux)] + public void CertificateDirectoryProperty() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Null(options.TrustedCertificatesDirectory); + + options.TrustedCertificatesDirectory = "."; + Assert.Equal(".", options.TrustedCertificatesDirectory); + } + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void CertificateDirectoryProperty_ThrowsPlatformNotSupportedException() + { + using (var connection = new LdapConnection("server")) + { + LdapSessionOptions options = connection.SessionOptions; + Assert.Throws(() => options.TrustedCertificatesDirectory = "CertificateDirectory"); + } + } +#endif } } From 6a30014ecd56927ec8f14da5186f9fc0777c16f5 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 27 Feb 2025 15:36:45 -0800 Subject: [PATCH 13/39] Fix getting resource when ResourceResolve returns assembly with resource that is an assembly ref (#112893) When getting a resource where `ResourceResolve` handler returns an assembly with a manifest resource that is an assembly ref, we incorrectly resolved the reference on the original assembly instead of the assembly returned by the handler and then also looked for the resource on the original assembly again instead of using the referenced assembly. This change includes a test for this case using IL. The manifest resource file (as opposed to assembly ref) case is already covered in libraries tests. --- src/coreclr/vm/peassembly.cpp | 24 +++++----- .../ManifestResourceAssemblyRef.il | 19 ++++++++ .../ManifestResourceAssemblyRef.ilproj | 8 ++++ .../ResourceResolve/ResourceAssembly.csproj | 8 ++++ .../Loader/ResourceResolve/ResourceResolve.cs | 47 +++++++++++++++++++ .../ResourceResolve/ResourceResolve.csproj | 10 ++++ 6 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.il create mode 100644 src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.ilproj create mode 100644 src/tests/Loader/ResourceResolve/ResourceAssembly.csproj create mode 100644 src/tests/Loader/ResourceResolve/ResourceResolve.cs create mode 100644 src/tests/Loader/ResourceResolve/ResourceResolve.csproj diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp index 3f54dbff556af2..8594e62c9a0e6b 100644 --- a/src/coreclr/vm/peassembly.cpp +++ b/src/coreclr/vm/peassembly.cpp @@ -518,7 +518,6 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, } CONTRACTL_END; - mdToken mdLinkRef; DWORD dwResourceFlags; DWORD dwOffset; @@ -567,30 +566,31 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, } - switch(TypeFromToken(mdLinkRef)) { + switch(TypeFromToken(mdLinkRef)) + { case mdtAssemblyRef: { if (pAssembly == NULL) return FALSE; AssemblySpec spec; - spec.InitializeSpec(mdLinkRef, GetMDImport(), pAssembly); - DomainAssembly* pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); + spec.InitializeSpec(mdLinkRef, pAssembly->GetMDImport(), pAssembly); + Assembly* pLoadedAssembly = spec.LoadAssembly(FILE_LOADED); if (dwLocation) { if (pAssemblyRef) - *pAssemblyRef = pDomainAssembly->GetAssembly(); + *pAssemblyRef = pLoadedAssembly; *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly } - return GetResource(szName, - cbResource, - pbInMemoryResource, - pAssemblyRef, - szFileName, - dwLocation, - pDomainAssembly->GetAssembly()); + return pLoadedAssembly->GetResource( + szName, + cbResource, + pbInMemoryResource, + pAssemblyRef, + szFileName, + dwLocation); } case mdtFile: diff --git a/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.il b/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.il new file mode 100644 index 00000000000000..c4891a07551f14 --- /dev/null +++ b/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.il @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) +} + +.assembly extern ResourceAssembly +{ + .publickeytoken = (00 00 00 00 00 00 00 00) +} + +.assembly ManifestResourceAssemblyRef { } + +.mresource public 'MyResource' +{ + .assembly extern 'ResourceAssembly' +} diff --git a/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.ilproj b/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.ilproj new file mode 100644 index 00000000000000..bfc5d0bb00df9b --- /dev/null +++ b/src/tests/Loader/ResourceResolve/ManifestResourceAssemblyRef.ilproj @@ -0,0 +1,8 @@ + + + library + + + + + diff --git a/src/tests/Loader/ResourceResolve/ResourceAssembly.csproj b/src/tests/Loader/ResourceResolve/ResourceAssembly.csproj new file mode 100644 index 00000000000000..e014b87610bd87 --- /dev/null +++ b/src/tests/Loader/ResourceResolve/ResourceAssembly.csproj @@ -0,0 +1,8 @@ + + + Library + + + + + diff --git a/src/tests/Loader/ResourceResolve/ResourceResolve.cs b/src/tests/Loader/ResourceResolve/ResourceResolve.cs new file mode 100644 index 00000000000000..2cf30a36216ffe --- /dev/null +++ b/src/tests/Loader/ResourceResolve/ResourceResolve.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Reflection; +using Xunit; + +[ConditionalClass(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotNativeAot))] +public unsafe class ResourceResolve +{ + [Fact] + [SkipOnMono("AssemblyRef manifest resource is not supported")] + public static void AssemblyRef() + { + string resourceName = "MyResource"; + Assembly assembly = typeof(ResourceResolve).Assembly; + + // Manifest resource is not in the current assembly + Stream stream = assembly.GetManifestResourceStream(resourceName); + Assert.Null(stream); + + // Handler returns assembly with a manifest resource assembly ref that + // points to another assembly with the resource + ResolveEventHandler handler = (sender, args) => + { + if (args.Name == resourceName && args.RequestingAssembly == assembly) + return Assembly.Load("ManifestResourceAssemblyRef"); + + return null; + }; + AppDomain.CurrentDomain.ResourceResolve += handler; + stream = assembly.GetManifestResourceStream(resourceName); + AppDomain.CurrentDomain.ResourceResolve -= handler; + Assert.NotNull(stream); + + // Verify that the stream matches the expected one in the resource assembly + Assembly resourceAssembly = Assembly.Load("ResourceAssembly"); + Stream expected = resourceAssembly.GetManifestResourceStream(resourceName); + Assert.Equal(expected.Length, stream.Length); + Span expectedBytes = new byte[expected.Length]; + expected.Read(expectedBytes); + Span streamBytes = new byte[stream.Length]; + stream.Read(streamBytes); + Assert.Equal(expectedBytes, streamBytes); + } +} diff --git a/src/tests/Loader/ResourceResolve/ResourceResolve.csproj b/src/tests/Loader/ResourceResolve/ResourceResolve.csproj new file mode 100644 index 00000000000000..5fc4c77bada41d --- /dev/null +++ b/src/tests/Loader/ResourceResolve/ResourceResolve.csproj @@ -0,0 +1,10 @@ + + + + + + + + + + From 8a346d2b0102e8b5da2bfe7e3328619999b309e1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:01:12 -0800 Subject: [PATCH 14/39] [release/9.0-staging] JIT: fix local assertion prop error for partial local comparisons (#112539) * JIT: fix local assertion prop error for partial local comparisons If a JTRUE comparison only involves part of a local value we cannot make assertions about the local as a whole. Fixes #111352. * restrict to TYP_LONG locals --------- Co-authored-by: Andy Ayers --- src/coreclr/jit/assertionprop.cpp | 16 +++++++ .../JitBlue/Runtime_111352/Runtime_111352.cs | 42 +++++++++++++++++++ .../Runtime_111352/Runtime_111352.csproj | 8 ++++ 3 files changed, 66 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 3d61a698a08d5c..f720ca6c826cba 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2211,6 +2211,22 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree) // If op1 is lcl and op2 is const or lcl, create assertion. if ((op1->gtOper == GT_LCL_VAR) && (op2->OperIsConst() || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483 { + // Watch out for cases where long local(s) are implicitly truncated. + // + LclVarDsc* const lcl1Dsc = lvaGetDesc(op1->AsLclVarCommon()); + if ((lcl1Dsc->TypeGet() == TYP_LONG) && (op1->TypeGet() != TYP_LONG)) + { + return NO_ASSERTION_INDEX; + } + if (op2->OperIs(GT_LCL_VAR)) + { + LclVarDsc* const lcl2Dsc = lvaGetDesc(op2->AsLclVarCommon()); + if ((lcl2Dsc->TypeGet() == TYP_LONG) && (op2->TypeGet() != TYP_LONG)) + { + return NO_ASSERTION_INDEX; + } + } + return optCreateJtrueAssertions(op1, op2, assertionKind); } else if (!optLocalAssertionProp) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs new file mode 100644 index 00000000000000..654b71021d4a73 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_111352 +{ + [Fact] + public static int Test1() => Problem1(0x1_0000_0001L, 0x2_0000_0001L); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int Problem1(long x, long y) + { + if ((uint)x == (uint)y) + { + if (x == y) + { + return -1; + } + } + + return 100; + } + + [Fact] + public static int Test2() => Problem2(0x1_0000_0000L); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int Problem2(long x) + { + if ((uint)x == 0) + { + if (x == 0) + { + return -1; + } + } + + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 1ac12eac8e70075654dabfdacf185f31b1901ce6 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 3 Mar 2025 09:36:41 -0800 Subject: [PATCH 15/39] Make CPU utilization checks in the thread pool configurable (#112791) - On Windows, checking CPU utilization seems to involve a small amount of overhead, which can become noticeable or even significant in some scenarios. This change makes the intervals of time over which CPU utilization is computed configurable. Increasing the interval increases the period at which CPU utilization is updated. The same config var can also be used to disable CPU utilization checks and have features that use it behave as though CPU utilization is low. - CPU utilization is used by the starvation heuristic and hill climbing. When CPU utilization is very high, the starvation heuristic reduces the rate of thread injection in starved cases. When CPU utilization is high, hill climbing avoids settling on higher thread count control values. - CPU utilization is currently updated when the gate thread performs periodic activities, which happens typically every 500 ms when a worker thread is active. There is one gate thread per .NET process. - In scenarios where there are many .NET processes running, and where many of them frequently but lightly use the thread pool, overall CPU usage may be relatively low, but the overhead from CPU utilization checks can bubble up to a noticeable portion of overall CPU usage. In a scenario involving 100s of .NET processes, it was seen that CPU utilization checks amount to 0.5-1% of overall CPU usage on the machine, which was considered significant. --- .../PortableThreadPool.GateThread.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs index 5d1b79a3098e05..d59cde103713e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs @@ -27,10 +27,26 @@ private static void GateThreadStart() bool debuggerBreakOnWorkStarvation = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.DebugBreakOnWorkerStarvation", false); + // CPU utilization is updated when the gate thread performs periodic activities (GateActivitiesPeriodMs), so + // that would also affect the actual interval. Set to 0 to disable using CPU utilization and have components + // behave as though CPU utilization is low. The default value of 1 causes CPU utilization to be updated whenever + // the gate thread performs periodic activities. + int cpuUtilizationIntervalMs = + AppContextConfigHelper.GetInt32Config( + "System.Threading.ThreadPool.CpuUtilizationIntervalMs", + "DOTNET_ThreadPool_CpuUtilizationIntervalMs", + defaultValue: 1, + allowNegative: false); + // The first reading is over a time range other than what we are focusing on, so we do not use the read other // than to send it to any runtime-specific implementation that may also use the CPU utilization. CpuUtilizationReader cpuUtilizationReader = default; - _ = cpuUtilizationReader.CurrentUtilization; + int lastCpuUtilizationRefreshTimeMs = 0; + if (cpuUtilizationIntervalMs > 0) + { + lastCpuUtilizationRefreshTimeMs = Environment.TickCount; + _ = cpuUtilizationReader.CurrentUtilization; + } PortableThreadPool threadPoolInstance = ThreadPoolInstance; LowLevelLock threadAdjustmentLock = threadPoolInstance._threadAdjustmentLock; @@ -102,8 +118,17 @@ private static void GateThreadStart() (uint)threadPoolInstance.GetAndResetHighWatermarkCountOfThreadsProcessingUserCallbacks()); } - int cpuUtilization = (int)cpuUtilizationReader.CurrentUtilization; - threadPoolInstance._cpuUtilization = cpuUtilization; + // Determine whether CPU utilization should be updated. CPU utilization is only used by the starvation + // heuristic and hill climbing, and neither of those are active when there is a pending blocking + // adjustment. + if (cpuUtilizationIntervalMs > 0 && + threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && + (uint)(currentTimeMs - lastCpuUtilizationRefreshTimeMs) >= (uint)cpuUtilizationIntervalMs) + { + lastCpuUtilizationRefreshTimeMs = currentTimeMs; + int cpuUtilization = (int)cpuUtilizationReader.CurrentUtilization; + threadPoolInstance._cpuUtilization = cpuUtilization; + } if (!disableStarvationDetection && threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && From f18ca7da01fd34472ee7f5a47cb05cfff7f04262 Mon Sep 17 00:00:00 2001 From: Aman Khalid Date: Tue, 4 Mar 2025 13:26:04 -0500 Subject: [PATCH 16/39] [release/9.0-staging] Backport "Ship CoreCLR packages in servicing releases" (#113026) --- src/coreclr/.nuget/Directory.Build.props | 5 ----- src/coreclr/.nuget/Directory.Build.targets | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/coreclr/.nuget/Directory.Build.props b/src/coreclr/.nuget/Directory.Build.props index 4a765f85b5bdcc..6f4d7a0cfb51dc 100644 --- a/src/coreclr/.nuget/Directory.Build.props +++ b/src/coreclr/.nuget/Directory.Build.props @@ -19,11 +19,6 @@ true - - - false - - diff --git a/src/coreclr/.nuget/Directory.Build.targets b/src/coreclr/.nuget/Directory.Build.targets index 379fbd65030b32..f30471ded8ae4f 100644 --- a/src/coreclr/.nuget/Directory.Build.targets +++ b/src/coreclr/.nuget/Directory.Build.targets @@ -4,7 +4,7 @@ $(ProductVersion) - $(PackageVersion) + $(PackageVersion) From d082f40569eb393658832fb14cffa3370b3a42db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 21:48:47 -0500 Subject: [PATCH 17/39] [release/9.0-staging] Fix TensorPrimitives.MultiplyAddEstimate for integers (#113094) --- .../TensorPrimitives.MultiplyAddEstimate.cs | 15 +- .../tests/TensorPrimitives.Generic.cs | 175 ++++++++++++++++-- .../tests/TensorPrimitivesTests.cs | 56 +++--- 3 files changed, 193 insertions(+), 53 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs index d3e651c160e881..b1bb7d379dcb5b 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MultiplyAddEstimate.cs @@ -128,9 +128,8 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z { return Vector128.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector128.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -149,9 +148,9 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z { if (typeof(T) == typeof(double)) return AdvSimd.Arm64.FusedMultiplyAdd(z.AsDouble(), x.AsDouble(), y.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -162,9 +161,8 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z { return Vector256.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector256.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -173,9 +171,9 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z if (typeof(T) == typeof(float)) return Fma.MultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); if (typeof(T) == typeof(double)) return Fma.MultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -186,9 +184,8 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z { return Vector512.MultiplyAddEstimate(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } - else + else if (typeof(T) == typeof(float)) { - Debug.Assert(typeof(T) == typeof(float)); return Vector512.MultiplyAddEstimate(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); } #else @@ -197,9 +194,9 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z if (typeof(T) == typeof(float)) return Avx512F.FusedMultiplyAdd(x.AsSingle(), y.AsSingle(), z.AsSingle()).As(); if (typeof(T) == typeof(double)) return Avx512F.FusedMultiplyAdd(x.AsDouble(), y.AsDouble(), z.AsDouble()).As(); } +#endif return (x * y) + z; -#endif } } } diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs index 94bbfb8fcebe92..2d3ce10a64d0e3 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitives.Generic.cs @@ -501,7 +501,7 @@ public void SpanDestinationFunctions_ThrowsForTooShortDestination(SpanDestinatio [Theory] [MemberData(nameof(SpanDestinationFunctionsToTest))] - public void SpanDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -639,7 +639,7 @@ public void SpanSpanDestination_ThrowsForTooShortDestination(SpanSpanDestination [Theory] [MemberData(nameof(SpanSpanDestinationFunctionsToTest))] - public void SpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -751,7 +751,7 @@ public void SpanScalarDestination_ThrowsForTooShortDestination(SpanScalarDestina [Theory] [MemberData(nameof(SpanScalarDestinationFunctionsToTest))] - public void SpanScalarDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -851,7 +851,7 @@ public void SpanScalarFloatDestination_ThrowsForTooShortDestination(ScalarSpanDe [Theory] [MemberData(nameof(ScalarSpanFloatDestinationFunctionsToTest))] - public void SpanScalarFloatDestination_ThrowsForOverlapppingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarFloatDestination_ThrowsForOverlappingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -949,7 +949,7 @@ public void SpanIntDestination_ThrowsForTooShortDestination(SpanScalarDestinatio [Theory] [MemberData(nameof(SpanIntDestinationFunctionsToTest))] - public void SpanIntDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanIntDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1091,7 +1091,7 @@ public void SpanSpanSpanDestination_ThrowsForTooShortDestination(SpanSpanSpanDes [Theory] [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] - public void SpanSpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1110,7 +1110,7 @@ public static IEnumerable SpanSpanScalarDestinationFunctionsToTest() { yield return Create(TensorPrimitives.FusedMultiplyAdd, T.FusedMultiplyAdd); yield return Create(TensorPrimitives.Lerp, T.Lerp); - yield return Create(TensorPrimitives.MultiplyAddEstimate, T.FusedMultiplyAdd, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); // TODO: Change T.FusedMultiplyAdd to T.MultiplyAddEstimate when available + yield return Create(TensorPrimitives.MultiplyAddEstimate, T.MultiplyAddEstimate, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); static object[] Create(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; @@ -1206,7 +1206,7 @@ public void SpanSpanScalarDestination_ThrowsForTooShortDestination(SpanSpanScala [Theory] [MemberData(nameof(SpanSpanScalarDestinationFunctionsToTest))] - public void SpanSpanScalarDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanSpanScalarDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanScalarDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1320,7 +1320,7 @@ public void SpanScalarSpanDestination_ThrowsForTooShortDestination(SpanScalarSpa [Theory] [MemberData(nameof(SpanScalarSpanDestinationFunctionsToTest))] - public void SpanScalarSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + public void SpanScalarSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanScalarSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) { _ = expectedMethod; _ = tolerance; @@ -1474,7 +1474,7 @@ public void SpanDestinationDestinationFunctions_ThrowsForTooShortDestination(Spa [Theory] [MemberData(nameof(SpanDestinationDestinationFunctionsToTest))] - public void SpanDestinationDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanDestinationDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; Assert.Throws(() => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(0, 2), array.AsSpan(4, 2))); @@ -1747,7 +1747,7 @@ public void SpanDestinationFunctions_ThrowsForTooShortDestination(SpanDestinatio [Theory] [MemberData(nameof(SpanDestinationFunctionsToTest))] - public void SpanDestinationFunctions_ThrowsForOverlapppingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanDestinationFunctions_ThrowsForOverlappingInputsWithOutputs(SpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(0, 2))); @@ -1833,7 +1833,7 @@ public void SpanSpanDestination_ThrowsForTooShortDestination(SpanSpanDestination [Theory] [MemberData(nameof(SpanSpanDestinationFunctionsToTest))] - public void SpanSpanDestination_ThrowsForOverlapppingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(0, 2))); @@ -1915,7 +1915,7 @@ public void SpanScalarDestination_ThrowsForTooShortDestination(SpanScalarDestina [Theory] [MemberData(nameof(SpanScalarDestinationFunctionsToTest))] - public void SpanScalarDestination_ThrowsForOverlapppingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) + public void SpanScalarDestination_ThrowsForOverlappingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; T y = NextRandom(); @@ -1924,6 +1924,149 @@ public void SpanScalarDestination_ThrowsForOverlapppingInputWithOutputs(SpanScal } #endregion + #region Span,Span,Span -> Destination + public static IEnumerable SpanSpanSpanDestinationFunctionsToTest() + { + yield return Create(TensorPrimitives.MultiplyAddEstimate, T.MultiplyAddEstimate, T.CreateTruncating(Helpers.DefaultToleranceForEstimates)); + + static object[] Create(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + => new object[] { tensorPrimitivesMethod, expectedMethod, tolerance }; + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_AllLengths(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengthsIncluding0, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + tensorPrimitivesMethod(x, y, z, destination); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_InPlace(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengthsIncluding0, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + T[] xOrig = x.Span.ToArray(); + + tensorPrimitivesMethod(x, x, x, x); + + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(xOrig[i], xOrig[i], xOrig[i]), x[i], tolerance); + } + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_SpecialValues(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, x); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, y); + + RunForEachSpecialValue(() => + { + tensorPrimitivesMethod(x.Span, y.Span, z.Span, destination.Span); + for (int i = 0; i < tensorLength; i++) + { + AssertEqualTolerance(expectedMethod(x[i], y[i], z[i]), destination[i], tolerance); + } + }, z); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForMismatchedLengths(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => tensorPrimitivesMethod(x, y, z, destination)); + Assert.Throws(() => tensorPrimitivesMethod(x, z, y, destination)); + Assert.Throws(() => tensorPrimitivesMethod(y, x, z, destination)); + Assert.Throws(() => tensorPrimitivesMethod(y, z, x, destination)); + Assert.Throws(() => tensorPrimitivesMethod(z, x, y, destination)); + Assert.Throws(() => tensorPrimitivesMethod(z, y, x, destination)); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForTooShortDestination(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + Assert.All(Helpers.TensorLengths, tensorLength => + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory z = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(x, y, z, destination)); + }); + } + + [Theory] + [MemberData(nameof(SpanSpanSpanDestinationFunctionsToTest))] + public void SpanSpanSpanDestination_ThrowsForOverlappingInputsWithOutputs(SpanSpanSpanDestinationDelegate tensorPrimitivesMethod, Func expectedMethod, T? tolerance = null) + { + _ = expectedMethod; + _ = tolerance; + + T[] array = new T[10]; + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(2, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(4, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(6, 2))); + AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(7, 2), array.AsSpan(8, 2))); + } + #endregion + #region Shifting/Rotating public static IEnumerable ShiftRotateDestinationFunctionsToTest() { @@ -1989,7 +2132,7 @@ public void ShiftRotateDestination_ThrowsForTooShortDestination(SpanScalarDestin [Theory] [MemberData(nameof(ShiftRotateDestinationFunctionsToTest))] - public void ShiftRotateDestination_ThrowsForOverlapppingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) + public void ShiftRotateDestination_ThrowsForOverlappingInputWithOutputs(SpanScalarDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(array.AsSpan(1, 2), default, array.AsSpan(0, 2))); @@ -2084,7 +2227,7 @@ public void CopySign_ThrowsForTooShortDestination() } [Fact] - public void CopySign_ThrowsForOverlapppingInputsWithOutputs() + public void CopySign_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; @@ -2347,7 +2490,7 @@ public void ScalarSpanDestination_ThrowsForTooShortDestination(ScalarSpanDestina [Theory] [MemberData(nameof(ScalarSpanDestinationFunctionsToTest))] - public void ScalarSpanDestination_ThrowsForOverlapppingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func _) + public void ScalarSpanDestination_ThrowsForOverlappingInputsWithOutputs(ScalarSpanDestinationDelegate tensorPrimitivesMethod, Func _) { T[] array = new T[10]; AssertExtensions.Throws("destination", () => tensorPrimitivesMethod(default, array.AsSpan(4, 2), array.AsSpan(3, 2))); diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs index 920ed00af7e90f..119f57a1f93759 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs @@ -236,7 +236,7 @@ public void Abs_ThrowsForTooShortDestination() } [Fact] - public void Abs_ThrowsForOverlapppingInputsWithOutputs() + public void Abs_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Abs(array.AsSpan(1, 5), array.AsSpan(0, 5))); @@ -307,7 +307,7 @@ public void Add_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Add_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Add_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Add(array.AsSpan(1, 2), array.AsSpan(5, 2), array.AsSpan(0, 2))); @@ -366,7 +366,7 @@ public void Add_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Add_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Add_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Add(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -442,7 +442,7 @@ public void AddMultiply_ThreeTensors_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_ThreeTensors_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_ThreeTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); @@ -520,7 +520,7 @@ public void AddMultiply_TensorTensorScalar_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_TensorTensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_TensorTensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), array.AsSpan(4, 2), default(T), array.AsSpan(0, 2))); @@ -596,7 +596,7 @@ public void AddMultiply_TensorScalarTensor_ThrowsForTooShortDestination() } [Fact] - public void AddMultiply_TensorScalarTensor_ThrowsForOverlapppingInputsWithOutputs() + public void AddMultiply_TensorScalarTensor_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => AddMultiply(array.AsSpan(1, 2), default(T), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -704,7 +704,7 @@ public void Cosh_ThrowsForTooShortDestination() } [Fact] - public void Cosh_ThrowsForOverlapppingInputsWithOutputs() + public void Cosh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -876,7 +876,7 @@ public void Divide_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Divide_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Divide_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Divide(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -935,7 +935,7 @@ public void Divide_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Divide_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Divide_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Divide(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -1066,7 +1066,7 @@ public void Exp_ThrowsForTooShortDestination() } [Fact] - public void Exp_ThrowsForOverlapppingInputsWithOutputs() + public void Exp_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1410,7 +1410,7 @@ public void Log_ThrowsForTooShortDestination() } [Fact] - public void Log_ThrowsForOverlapppingInputsWithOutputs() + public void Log_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1495,7 +1495,7 @@ public void Log2_ThrowsForTooShortDestination() } [Fact] - public void Log2_ThrowsForOverlapppingInputsWithOutputs() + public void Log2_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -1682,7 +1682,7 @@ public void Max_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Max_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Max_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Max(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -1869,7 +1869,7 @@ public void MaxMagnitude_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void MaxMagnitude_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MaxMagnitude_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MaxMagnitude(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2056,7 +2056,7 @@ public void Min_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Min_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Min_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Min(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2241,7 +2241,7 @@ public void MinMagnitude_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void MinMagnitude_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MinMagnitude_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MinMagnitude(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2315,7 +2315,7 @@ public void Multiply_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Multiply_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Multiply_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Multiply(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2374,7 +2374,7 @@ public void Multiply_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Multiply_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Multiply_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Multiply(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -2450,7 +2450,7 @@ public void MultiplyAdd_ThreeTensors_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_ThreeTensors_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_ThreeTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(7, 2), array.AsSpan(0, 2))); @@ -2513,7 +2513,7 @@ public void MultiplyAdd_TensorTensorScalar_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_TensorTensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_TensorTensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), array.AsSpan(4, 2), default(T), array.AsSpan(0, 2))); @@ -2574,7 +2574,7 @@ public void MultiplyAdd_TensorScalarTensor_ThrowsForTooShortDestination() } [Fact] - public void MultiplyAdd_TensorScalarTensor_ThrowsForOverlapppingInputsWithOutputs() + public void MultiplyAdd_TensorScalarTensor_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => MultiplyAdd(array.AsSpan(1, 2), default(T), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -2632,7 +2632,7 @@ public void Negate_ThrowsForTooShortDestination() } [Fact] - public void Negate_ThrowsForOverlapppingInputsWithOutputs() + public void Negate_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Negate(array.AsSpan(1, 2), array.AsSpan(0, 2))); @@ -2827,7 +2827,7 @@ public void Sigmoid_ThrowsForEmptyInput() } [Fact] - public void Sigmoid_ThrowsForOverlapppingInputsWithOutputs() + public void Sigmoid_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -2935,7 +2935,7 @@ public void Sinh_ThrowsForTooShortDestination() } [Fact] - public void Sinh_ThrowsForOverlapppingInputsWithOutputs() + public void Sinh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -3019,7 +3019,7 @@ public void SoftMax_ThrowsForEmptyInput() } [Fact] - public void SoftMax_ThrowsForOverlapppingInputsWithOutputs() + public void SoftMax_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; @@ -3093,7 +3093,7 @@ public void Subtract_TwoTensors_ThrowsForTooShortDestination() } [Fact] - public void Subtract_TwoTensors_ThrowsForOverlapppingInputsWithOutputs() + public void Subtract_TwoTensors_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Subtract(array.AsSpan(1, 2), array.AsSpan(4, 2), array.AsSpan(0, 2))); @@ -3152,7 +3152,7 @@ public void Subtract_TensorScalar_ThrowsForTooShortDestination() } [Fact] - public void Subtract_TensorScalar_ThrowsForOverlapppingInputsWithOutputs() + public void Subtract_TensorScalar_ThrowsForOverlappingInputsWithOutputs() { T[] array = new T[10]; AssertExtensions.Throws("destination", () => Subtract(array.AsSpan(1, 2), default(T), array.AsSpan(0, 2))); @@ -3317,7 +3317,7 @@ public void Tanh_ThrowsForTooShortDestination() } [Fact] - public void Tanh_ThrowsForOverlapppingInputsWithOutputs() + public void Tanh_ThrowsForOverlappingInputsWithOutputs() { if (!IsFloatingPoint) return; From a5d80ca93d7f3823c7454fd7d5b7dd58d88bf8be Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 6 Mar 2025 10:59:41 -0500 Subject: [PATCH 18/39] Use invariant culture when formatting transfer capture in regex source generator (#113081) (#113150) A balancing group can result in TransferCapture being emitted with a negative "capnum". If the compiler is running under a culture that uses something other than '-' as the negative sign, the resulting generated code will fail to compile. --- .../gen/RegexGenerator.Emitter.cs | 2 +- .../RegexGeneratorHelper.netcoreapp.cs | 29 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index a64b43d6884737..54db918d6bae7a 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -2549,7 +2549,7 @@ void EmitCapture(RegexNode node, RegexNode? subsequent = null) } else { - writer.WriteLine($"base.TransferCapture({capnum}, {uncapnum}, {startingPos}, pos);"); + writer.WriteLine($"base.TransferCapture({capnum.ToString(CultureInfo.InvariantCulture)}, {uncapnum}, {startingPos}, pos);"); } if (isAtomic || !childBacktracks) diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs index fe0e793819f646..90e638570f629f 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs @@ -134,6 +134,12 @@ internal static async Task SourceGenRegexAsync( return results[0]; } + private static readonly CultureInfo s_cultureWithMinusNegativeSign = new CultureInfo("") + { + // To validate that generation still succeeds even when something other than '-' is used. + NumberFormat = new NumberFormatInfo() { NegativeSign = $"{(char)0x2212}" } + }; + internal static async Task SourceGenRegexAsync( (string pattern, CultureInfo? culture, RegexOptions? options, TimeSpan? matchTimeout)[] regexes, CancellationToken cancellationToken = default) { @@ -214,13 +220,24 @@ internal static async Task SourceGenRegexAsync( comp = comp.ReplaceSyntaxTree(comp.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(SourceText.From(code.ToString(), Encoding.UTF8), s_previewParseOptions)); // Run the generator - GeneratorDriverRunResult generatorResults = s_generatorDriver.RunGenerators(comp!, cancellationToken).GetRunResult(); - ImmutableArray generatorDiagnostics = generatorResults.Diagnostics.RemoveAll(d => d.Severity <= DiagnosticSeverity.Hidden); - if (generatorDiagnostics.Length != 0) + CultureInfo origCulture = CultureInfo.CurrentCulture; + CultureInfo.CurrentCulture = s_cultureWithMinusNegativeSign; + GeneratorDriverRunResult generatorResults; + ImmutableArray generatorDiagnostics; + try { - throw new ArgumentException( - string.Join(Environment.NewLine, generatorResults.GeneratedTrees.Select(t => NumberLines(t.ToString()))) + Environment.NewLine + - string.Join(Environment.NewLine, generatorDiagnostics)); + generatorResults = s_generatorDriver.RunGenerators(comp!, cancellationToken).GetRunResult(); + generatorDiagnostics = generatorResults.Diagnostics.RemoveAll(d => d.Severity <= DiagnosticSeverity.Hidden); + if (generatorDiagnostics.Length != 0) + { + throw new ArgumentException( + string.Join(Environment.NewLine, generatorResults.GeneratedTrees.Select(t => NumberLines(t.ToString()))) + Environment.NewLine + + string.Join(Environment.NewLine, generatorDiagnostics)); + } + } + finally + { + CultureInfo.CurrentCulture = origCulture; } // Compile the assembly to a stream From 296586bdb1e295eb9f328d279aa33f2932ca6c00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:18:45 -0800 Subject: [PATCH 19/39] [release/9.0-staging] NativeAOT/Arm64: Do not overwrite gcinfo tracking registers for TLS (#112549) * Do not overwrite gcrefs masks present in reg1/reg2 fields * Temporary use debian 10 * Revert "Temporary use debian 10" This reverts commit 269225f46b97d0d511510688504658b695e86822. --------- Co-authored-by: Kunal Pathak Co-authored-by: Jeff Schwartz --- src/coreclr/jit/emitarm64.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 2a5c947de175c5..624a737234fcbb 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -217,7 +217,6 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && id->idIsTlsGD()) { - assert(isGeneralRegister(id->idReg1())); assert(id->idAddr()->iiaAddr != nullptr); } else @@ -9184,11 +9183,14 @@ void emitter::emitIns_Call(EmitCallType callType, if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && EA_IS_CNS_TLSGD_RELOC(retSize)) { // For NativeAOT linux/arm64, we need to also record the relocation of methHnd. - // Since we do not have space to embed it in instrDesc, we store the register in - // reg1 and instead use the `iiaAdd` to store the method handle. Likewise, during - // emitOutputInstr, we retrieve the register from reg1 for this specific case. + // Since we do not have space to embed it in instrDesc, we use the `iiaAddr` to + // store the method handle. + // The target handle need to be always in R2 and hence the assert check. + // We cannot use reg1 and reg2 fields of instrDesc because they contain the gc + // registers (emitEncodeCallGCregs()) that are live across the call. + + assert(ireg == REG_R2); id->idSetTlsGD(); - id->idReg1(ireg); id->idAddr()->iiaAddr = (BYTE*)methHnd; } else @@ -10990,12 +10992,13 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { emitRecordRelocation(odst, (CORINFO_METHOD_HANDLE)id->idAddr()->iiaAddr, IMAGE_REL_AARCH64_TLSDESC_CALL); - code |= insEncodeReg_Rn(id->idReg1()); // nnnnn + code |= insEncodeReg_Rn(REG_R2); // nnnnn } else { code |= insEncodeReg_Rn(id->idReg3()); // nnnnn } + dst += emitOutputCall(ig, dst, id, code); sz = id->idIsLargeCall() ? sizeof(instrDescCGCA) : sizeof(instrDesc); break; @@ -13315,7 +13318,15 @@ void emitter::emitDispInsHelp( case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn // The size of a branch target is always EA_PTRSIZE assert(insOptsNone(id->idInsOpt())); - emitDispReg(id->idReg3(), EA_PTRSIZE, false); + + if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && id->idIsTlsGD()) + { + emitDispReg(REG_R2, EA_PTRSIZE, false); + } + else + { + emitDispReg(id->idReg3(), EA_PTRSIZE, false); + } break; case IF_LS_1A: // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB) From 4408376420c23fb600a7fa71ba597b3431257d88 Mon Sep 17 00:00:00 2001 From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com> Date: Fri, 7 Mar 2025 09:32:53 -0800 Subject: [PATCH 20/39] Update branding to 9.0.4 (#113226) --- eng/Versions.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 9bc7f6caeff393..a9e557082c3fdd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 9.0.3 + 9.0.4 9 0 - 3 + 4 9.0.100 8.0.$([MSBuild]::Add($(PatchVersion),11)) 7.0.20 From a0eb8bf1e2c85f05308fd6e848d608b2a51b2646 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Fri, 7 Mar 2025 11:13:03 -0800 Subject: [PATCH 21/39] [9.0] Make counting of IO completion work items more precise on Windows (#112794) * Stop counting work items from ThreadPoolTypedWorkItemQueue for ThreadPool.CompletedWorkItemCount (#106854) * Stop counting work items from ThreadPoolTypedWorkItemQueue as completed work items --------- Co-authored-by: Eduardo Manuel Velarde Polar Co-authored-by: Koundinya Veluri * Make counting of IO completion work items more precise on Windows - Follow-up to https://github.com/dotnet/runtime/pull/106854. Issue: https://github.com/dotnet/runtime/issues/104284. - Before the change, the modified test case often yields 5 or 6 completed work items, due to queue-processing work items that happen to not process any user work items. After the change, it always yields 4. - Looks like it doesn't hurt to have more-precise counting, and there was a request to backport a fix to .NET 8, where it's more necessary to fix the issue --------- Co-authored-by: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Co-authored-by: Eduardo Manuel Velarde Polar --- .../Threading/ThreadInt64PersistentCounter.cs | 35 ++++++++++++++++-- .../System/Threading/ThreadPoolWorkQueue.cs | 9 ++++- .../tests/ThreadPoolTests.cs | 36 +++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs index 0f7fbc06a9a8eb..29cf2dce305657 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs @@ -15,6 +15,7 @@ internal sealed class ThreadInt64PersistentCounter private static List? t_nodeFinalizationHelpers; private long _overflowCount; + private long _lastReturnedCount; // dummy node serving as a start and end of the ring list private readonly ThreadLocalNode _nodes; @@ -31,6 +32,13 @@ public static void Increment(object threadLocalCountObject) Unsafe.As(threadLocalCountObject).Increment(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decrement(object threadLocalCountObject) + { + Debug.Assert(threadLocalCountObject is ThreadLocalNode); + Unsafe.As(threadLocalCountObject).Decrement(); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Add(object threadLocalCountObject, uint count) { @@ -76,6 +84,17 @@ public long Count count += node.Count; node = node._next; } + + // Ensure that the returned value is monotonically increasing + long lastReturnedCount = _lastReturnedCount; + if (count > lastReturnedCount) + { + _lastReturnedCount = count; + } + else + { + count = lastReturnedCount; + } } finally { @@ -134,6 +153,18 @@ public void Increment() OnAddOverflow(1); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Decrement() + { + if (_count != 0) + { + _count--; + return; + } + + OnAddOverflow(-1); + } + public void Add(uint count) { Debug.Assert(count != 0); @@ -149,7 +180,7 @@ public void Add(uint count) } [MethodImpl(MethodImplOptions.NoInlining)] - private void OnAddOverflow(uint count) + private void OnAddOverflow(long count) { Debug.Assert(count != 0); @@ -161,7 +192,7 @@ private void OnAddOverflow(uint count) counter._lock.Acquire(); try { - counter._overflowCount += (long)_count + count; + counter._overflowCount += _count + count; _count = 0; } finally diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 6fa669046a1f06..7660d427da63fd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1375,6 +1375,9 @@ void IThreadPoolWorkItem.Execute() Debug.Assert(stageBeforeUpdate != QueueProcessingStage.NotScheduled); if (stageBeforeUpdate == QueueProcessingStage.Determining) { + // Discount a work item here to avoid counting this queue processing work item + ThreadInt64PersistentCounter.Decrement( + ThreadPoolWorkQueueThreadLocals.threadLocals!.threadLocalCompletionCountObject!); return; } } @@ -1414,7 +1417,11 @@ void IThreadPoolWorkItem.Execute() currentThread.ResetThreadPoolThread(); } - ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount); + // Discount a work item here to avoid counting this queue processing work item + if (completedCount > 1) + { + ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount - 1); + } } } diff --git a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs index f9e454abbe8a64..a59997f8e3f8b3 100644 --- a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs +++ b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs @@ -1462,6 +1462,42 @@ static async Task RunAsyncIOTest() }, ioCompletionPortCount.ToString()).Dispose(); } + + [ConditionalFact(nameof(IsThreadingAndRemoteExecutorSupported))] + [PlatformSpecific(TestPlatforms.Windows)] + public static unsafe void ThreadPoolCompletedWorkItemCountTest() + { + // Run in a separate process to test in a clean thread pool environment such that we don't count external work items + RemoteExecutor.Invoke(() => + { + const int WorkItemCount = 4; + + int completedWorkItemCount = 0; + using var allWorkItemsCompleted = new AutoResetEvent(false); + + IOCompletionCallback callback = + (errorCode, numBytes, innerNativeOverlapped) => + { + Overlapped.Free(innerNativeOverlapped); + if (Interlocked.Increment(ref completedWorkItemCount) == WorkItemCount) + { + allWorkItemsCompleted.Set(); + } + }; + for (int i = 0; i < WorkItemCount; i++) + { + ThreadPool.UnsafeQueueNativeOverlapped(new Overlapped().Pack(callback, null)); + } + + allWorkItemsCompleted.CheckedWait(); + + // Allow work items to be marked as completed during this time + ThreadTestHelpers.WaitForCondition(() => ThreadPool.CompletedWorkItemCount >= WorkItemCount); + Thread.Sleep(50); + Assert.Equal(WorkItemCount, ThreadPool.CompletedWorkItemCount); + }).Dispose(); + } + public static bool IsThreadingAndRemoteExecutorSupported => PlatformDetection.IsThreadingSupported && RemoteExecutor.IsSupported; From f4fd947a03efd877d6e3b4db38d54ac392494ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Sat, 8 Mar 2025 09:08:02 +0100 Subject: [PATCH 22/39] [release/9.0-staging] Remove --no-lock brew flag (#113281) Backport of https://github.com/dotnet/runtime/pull/113280 --- eng/install-native-dependencies.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh index 41895e0b9254c8..f8c9db632860de 100755 --- a/eng/install-native-dependencies.sh +++ b/eng/install-native-dependencies.sh @@ -44,7 +44,7 @@ case "$os" in export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 # Skip brew update for now, see https://github.com/actions/setup-python/issues/577 # brew update --preinstall - brew bundle --no-upgrade --no-lock --file "$(dirname "$0")/Brewfile" + brew bundle --no-upgrade --file "$(dirname "$0")/Brewfile" ;; *) From 34ed4b33bf232a85352fbf0604c1570db76a5c03 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 09:57:06 +0100 Subject: [PATCH 23/39] Update MsQuic library version (#113205) Co-authored-by: ManickaP --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 9bc7f6caeff393..a218260b59a588 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -222,7 +222,7 @@ 9.0.0-rtm.25105.1 9.0.0-rtm.24466.4 - 2.4.3 + 2.4.8 9.0.0-alpha.1.24167.3 19.1.0-alpha.1.24575.1 From 67cbfaac4cf32cc0a47fbd4c3b1d02688a5a4ed4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:05:25 -0700 Subject: [PATCH 24/39] Update branding to 9.0.4 (#113226) (#113264) Co-authored-by: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com> --- eng/Versions.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index a218260b59a588..37a73f6624f245 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 9.0.3 + 9.0.4 9 0 - 3 + 4 9.0.100 8.0.$([MSBuild]::Add($(PatchVersion),11)) 7.0.20 From 08bad6edf33bda5e7eff81ae62b6096c463a2d5d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:06:48 -0700 Subject: [PATCH 25/39] Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20250223.3 (#112836) Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.25076.3 -> To Version 3.11.0-beta1.25123.3 Co-authored-by: dotnet-maestro[bot] --- NuGet.config | 19 +------------------ eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/NuGet.config b/NuGet.config index 7a77a883fb2871..617e5988a39de4 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,25 +9,8 @@ - - - - - - - - - - - - - - - - - - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8de3216106088b..ed39e57bce3fb1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -372,11 +372,11 @@ https://github.com/dotnet/roslyn 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 diff --git a/eng/Versions.props b/eng/Versions.props index 37a73f6624f245..416a51a7f0a5c6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,8 +36,8 @@ - 3.11.0-beta1.25076.3 - 9.0.0-preview.25076.3 + 3.11.0-beta1.25123.3 + 9.0.0-preview.25123.3 - diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ed39e57bce3fb1..f5dae4adaee7a5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -360,17 +360,17 @@ https://github.com/dotnet/runtime-assets ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 https://github.com/dotnet/roslyn-analyzers @@ -381,9 +381,9 @@ 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn - 25acc509a1cb1d1a4923b0091cbc5ce837b024d0 + 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 diff --git a/eng/Versions.props b/eng/Versions.props index 416a51a7f0a5c6..028ab7245d1627 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,9 +44,9 @@ Any tools that contribute to the design-time experience should use the MicrosoftCodeAnalysisVersion_LatestVS property above to ensure they do not break the local dev experience. --> - 4.12.0-3.25105.5 - 4.12.0-3.25105.5 - 4.12.0-3.25105.5 + 4.12.0-3.25124.2 + 4.12.0-3.25124.2 + 4.12.0-3.25124.2 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.25103.3 - 9.0.0-prerelease.25103.3 - 9.0.0-prerelease.25103.3 + 9.0.0-prerelease.25113.3 + 9.0.0-prerelease.25113.3 + 9.0.0-prerelease.25113.3 9.0.0-alpha.0.25077.3 3.12.0 4.5.0 From 5eddbbcc8aafc44463b87accfd4651c78202ab39 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:15:05 -0700 Subject: [PATCH 28/39] Update dependencies from https://github.com/dotnet/runtime-assets build 20250213.2 (#112552) Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 9.0.0-beta.25071.2 -> To Version 9.0.0-beta.25113.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 56 ++++++++++++++++++++--------------------- eng/Versions.props | 28 ++++++++++----------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9b15bccdd45f3c..2ecebeca757e3f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -174,57 +174,57 @@ https://github.com/dotnet/arcade bac7e1caea791275b7c3ccb4cb75fd6a04a26618 - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e https://github.com/dotnet/llvm-project @@ -356,9 +356,9 @@ https://github.com/dotnet/hotreload-utils fe67b0da4c0a7e82f0f9a4da1cb966c730e6934f - + https://github.com/dotnet/runtime-assets - ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 + 739921bd3405841c06d3f74701c9e6ccfbd19e2e https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index 57d58781386c25..fb84bea59651ba 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -141,20 +141,20 @@ 8.0.0 8.0.0 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 - 9.0.0-beta.25071.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 + 9.0.0-beta.25113.2 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 From a104fda0f300009a9cfe4c57c7c9c6e3b9dd0183 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:15:48 -0700 Subject: [PATCH 29/39] [release/9.0] Update dependencies from dotnet/emsdk (#112522) * Update dependencies from https://github.com/dotnet/emsdk build 20250213.2 Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100 , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100.Transport From Version 9.0.3-servicing.25105.2 -> To Version 9.0.3-servicing.25113.2 * Update dependencies from https://github.com/dotnet/emsdk build 20250214.2 Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100 , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100.Transport From Version 9.0.3-servicing.25105.2 -> To Version 9.0.3-servicing.25114.2 Dependency coherency updates runtime.linux-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools From Version 19.1.0-alpha.1.24575.1 -> To Version 19.1.0-alpha.1.25113.2 (parent: Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100.Transport * Update dependencies from https://github.com/dotnet/emsdk build 20250307.2 Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100 , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100.Transport From Version 9.0.3-servicing.25105.2 -> To Version 9.0.4-servicing.25157.2 --------- Co-authored-by: dotnet-maestro[bot] --- NuGet.config | 21 +-------- eng/Version.Details.xml | 100 ++++++++++++++++++++-------------------- eng/Versions.props | 48 +++++++++---------- 3 files changed, 75 insertions(+), 94 deletions(-) diff --git a/NuGet.config b/NuGet.config index 7a77a883fb2871..a09e522305d1c8 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,28 +9,9 @@ - - - - - - - - - - - - - - - - - - - + - - + https://github.com/dotnet/emsdk - dad5528e5bdf92a05a5a404c5f7939523390b96d + 78be8cdf4f0bfd93018fd7a87f8282a41d041298 @@ -226,61 +226,61 @@ https://github.com/dotnet/runtime-assets ceeaaca3ae019d656421fdf49fc2dde5f29c9d09 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 - + https://github.com/dotnet/llvm-project - d1f598a5c2922be959c9a21cd50adc2fa780f064 + f98a0db595fe3f28dac4594acc7114b16281d090 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index a9e557082c3fdd..149de3734cac2c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -225,39 +225,39 @@ 2.4.3 9.0.0-alpha.1.24167.3 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 - 9.0.3-servicing.25105.2 - 9.0.3 + 9.0.4-servicing.25157.2 + 9.0.4 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100Version) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 - 19.1.0-alpha.1.24575.1 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25113.2 3.1.7 1.0.406601 From 7a2ef65a23f4b296b1d17863b5903d03b96908dc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:16:22 -0700 Subject: [PATCH 30/39] Update dependencies from https://github.com/dotnet/cecil build 20250212.2 (#112515) Microsoft.SourceBuild.Intermediate.cecil , Microsoft.DotNet.Cecil From Version 0.11.5-alpha.25102.5 -> To Version 0.11.5-alpha.25112.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2ecebeca757e3f..3b6640c4ba5a4e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -54,14 +54,14 @@ 803d8598f98fb4efd94604b32627ee9407f246db - + https://github.com/dotnet/cecil - aa3ae0d49da3cfb31a383f16303a3f2f0c3f1a19 + 8debcd23b73a27992a5fdb2229f546e453619d11 - + https://github.com/dotnet/cecil - aa3ae0d49da3cfb31a383f16303a3f2f0c3f1a19 + 8debcd23b73a27992a5fdb2229f546e453619d11 diff --git a/eng/Versions.props b/eng/Versions.props index fb84bea59651ba..52a54c102ec99a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -215,7 +215,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25102.5 + 0.11.5-alpha.25112.2 9.0.0-rtm.24511.16 From 1bb31dca78b40b3a575335f296a2e7fc48ec6d85 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:17:44 -0700 Subject: [PATCH 31/39] [release/9.0-staging] Update dependencies from dotnet/arcade (#112468) * Update dependencies from https://github.com/dotnet/arcade build 20250211.5 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.25077.4 -> To Version 9.0.0-beta.25111.5 * Make the workload sdk follow the sdk flow --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 84 ++++++++++++++++++++--------------------- eng/Versions.props | 36 +++++++++--------- global.json | 10 ++--- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3b6640c4ba5a4e..4ea96e800643df 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -92,87 +92,87 @@ - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 https://github.com/dotnet/runtime-assets @@ -332,9 +332,9 @@ https://github.com/dotnet/xharness edc52ac68c1bf77e3b107fc8a448674a6d058d8a - + https://github.com/dotnet/arcade - bac7e1caea791275b7c3ccb4cb75fd6a04a26618 + 5da211e1c42254cb35e7ef3d5a8428fb24853169 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 52a54c102ec99a..b6f2ead1ae0fe1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,22 +85,22 @@ 9.0.103 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 2.9.0-beta.25077.4 - 9.0.0-beta.25077.4 - 2.9.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 - 9.0.0-beta.25077.4 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 2.9.0-beta.25111.5 + 9.0.0-beta.25111.5 + 2.9.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 + 9.0.0-beta.25111.5 1.4.0 @@ -262,8 +262,8 @@ 3.1.7 1.0.406601 - - 9.0.102 + $(MicrosoftDotNetApiCompatTaskVersion) + 9.0.0-alpha.1.24175.1 $(MicrosoftNETRuntimeEmscriptenVersion) $(runtimewinx64MicrosoftNETCoreRuntimeWasmNodeTransportPackageVersion) diff --git a/global.json b/global.json index 4f7a01b1c6f48a..8cf149480ba5d3 100644 --- a/global.json +++ b/global.json @@ -1,16 +1,16 @@ { "sdk": { - "version": "9.0.102", + "version": "9.0.103", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "9.0.102" + "dotnet": "9.0.103" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25077.4", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25077.4", - "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25077.4", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25111.5", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25111.5", + "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25111.5", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "9.0.0-rtm.24511.16" From b5f9b09410b604010270a4ebfe532d6c0bbbf071 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:18:12 -0700 Subject: [PATCH 32/39] [release/9.0-staging] Update dependencies from dotnet/icu (#112514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from https://github.com/dotnet/icu build 20250212.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-rtm.25105.1 -> To Version 9.0.0-rtm.25112.1 * Update dependencies from https://github.com/dotnet/icu build 20250213.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-rtm.25105.1 -> To Version 9.0.0-rtm.25113.1 * Update dependencies from https://github.com/dotnet/icu build 20250214.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-rtm.25105.1 -> To Version 9.0.0-rtm.25114.1 * Update dependencies from https://github.com/dotnet/icu build 20250307.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-rtm.25105.1 -> To Version 9.0.0-rtm.25157.1 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- NuGet.config | 1 - eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 9eb2a590d6bd92..937f423c99ca1e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -12,7 +12,6 @@ - 9.0.0-rtm.24511.16 - 9.0.0-rtm.25105.1 + 9.0.0-rtm.25157.1 9.0.0-rtm.24466.4 2.4.8 From b64f47acecdfe03a03b880eeb0ebd69ca9468945 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:19:49 -0700 Subject: [PATCH 33/39] [release/9.0-staging] Update dependencies from dotnet/hotreload-utils (#112394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from https://github.com/dotnet/hotreload-utils build 20250210.2 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.25077.3 -> To Version 9.0.0-alpha.0.25110.2 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20250213.2 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.25077.3 -> To Version 9.0.0-alpha.0.25113.2 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20250224.3 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.25077.3 -> To Version 9.0.0-alpha.0.25124.3 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20250303.2 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.25077.3 -> To Version 9.0.0-alpha.0.25153.2 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fcffa2bcff5ff7..ed4b1b031e835a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -352,9 +352,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://github.com/dotnet/hotreload-utils - fe67b0da4c0a7e82f0f9a4da1cb966c730e6934f + fd21b154f1152569e7fa49a4e030927eccbf4aaa https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 45778b9d7c4f86..f53f489e44824b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -187,7 +187,7 @@ 9.0.0-prerelease.25113.3 9.0.0-prerelease.25113.3 9.0.0-prerelease.25113.3 - 9.0.0-alpha.0.25077.3 + 9.0.0-alpha.0.25153.2 3.12.0 4.5.0 6.0.0 From 8670c12404f25255000a64f4d2f2a2fb06d44ee8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 12:10:14 -0700 Subject: [PATCH 34/39] [release/9.0] Fix `BigInteger.Rotate{Left,Right}` for backport (#112991) * Add BigInteger.Rotate* tests * Fix BigInteger.Rotate* * avoid stackalloc * Add comment * Fix the unsigned right shift operator of BigInteger (#112879) * Add tests for the shift operator of BigInteger * Fix the unsigned right shift operator of BigInteger * avoid stackalloc * external sign element --------- Co-authored-by: kzrnm --- .../src/System/Numerics/BigInteger.cs | 115 +++- .../tests/BigInteger/MyBigInt.cs | 162 +++++ .../tests/BigInteger/Rotate.cs | 629 ++++++++++++++++++ .../tests/BigInteger/op_leftshift.cs | 64 ++ .../tests/BigInteger/op_rightshift.cs | 265 +++++--- .../tests/BigInteger/stackcalculator.cs | 8 +- .../System.Runtime.Numerics.Tests.csproj | 1 + 7 files changed, 1123 insertions(+), 121 deletions(-) create mode 100644 src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index b3355ff68678ca..e173705da39c47 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -1694,7 +1694,7 @@ private static BigInteger Add(ReadOnlySpan leftBits, int leftSign, ReadOnl } if (bitsFromPool != null) - ArrayPool.Shared.Return(bitsFromPool); + ArrayPool.Shared.Return(bitsFromPool); return result; } @@ -2629,7 +2629,7 @@ public static implicit operator BigInteger(nuint value) if (zdFromPool != null) ArrayPool.Shared.Return(zdFromPool); - exit: + exit: if (xdFromPool != null) ArrayPool.Shared.Return(xdFromPool); @@ -3232,7 +3232,27 @@ public static BigInteger PopCount(BigInteger value) public static BigInteger RotateLeft(BigInteger value, int rotateAmount) { value.AssertValid(); - int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); + + bool negx = value._sign < 0; + uint smallBits = NumericsHelpers.Abs(value._sign); + scoped ReadOnlySpan bits = value._bits; + if (bits.IsEmpty) + { + bits = new ReadOnlySpan(in smallBits); + } + + int xl = bits.Length; + if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1))) + { + // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion. + // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00] + // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back. + // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back + // If the 2's component's last element is a 0, we will track the sign externally + ++xl; + } + + int byteCount = xl * 4; // Normalize the rotate amount to drop full rotations rotateAmount = (int)(rotateAmount % (byteCount * 8L)); @@ -3249,14 +3269,13 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) (int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint); uint[]? xdFromPool = null; - int xl = value._bits?.Length ?? 1; - Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold) ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] : xdFromPool = ArrayPool.Shared.Rent(xl); xd = xd.Slice(0, xl); + xd[^1] = 0; - bool negx = value.GetPartsForBitManipulation(xd); + bits.CopyTo(xd); int zl = xl; uint[]? zdFromPool = null; @@ -3367,7 +3386,28 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) public static BigInteger RotateRight(BigInteger value, int rotateAmount) { value.AssertValid(); - int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); + + + bool negx = value._sign < 0; + uint smallBits = NumericsHelpers.Abs(value._sign); + scoped ReadOnlySpan bits = value._bits; + if (bits.IsEmpty) + { + bits = new ReadOnlySpan(in smallBits); + } + + int xl = bits.Length; + if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1))) + { + // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion. + // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00] + // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back. + // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back + // If the 2's component's last element is a 0, we will track the sign externally + ++xl; + } + + int byteCount = xl * 4; // Normalize the rotate amount to drop full rotations rotateAmount = (int)(rotateAmount % (byteCount * 8L)); @@ -3384,14 +3424,13 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) (int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint); uint[]? xdFromPool = null; - int xl = value._bits?.Length ?? 1; - Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold) ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] : xdFromPool = ArrayPool.Shared.Rent(xl); xd = xd.Slice(0, xl); + xd[^1] = 0; - bool negx = value.GetPartsForBitManipulation(xd); + bits.CopyTo(xd); int zl = xl; uint[]? zdFromPool = null; @@ -3438,19 +3477,12 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) { int carryShift = kcbitUint - smallShift; - int dstIndex = 0; - int srcIndex = digitShift; + int dstIndex = xd.Length - 1; + int srcIndex = digitShift == 0 + ? xd.Length - 1 + : digitShift - 1; - uint carry = 0; - - if (digitShift == 0) - { - carry = xd[^1] << carryShift; - } - else - { - carry = xd[srcIndex - 1] << carryShift; - } + uint carry = xd[digitShift] << carryShift; do { @@ -3459,22 +3491,22 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) zd[dstIndex] = (part >> smallShift) | carry; carry = part << carryShift; - dstIndex++; - srcIndex++; + dstIndex--; + srcIndex--; } - while (srcIndex < xd.Length); + while ((uint)srcIndex < (uint)xd.Length); // is equivalent to (srcIndex >= 0 && srcIndex < xd.Length) - srcIndex = 0; + srcIndex = xd.Length - 1; - while (dstIndex < zd.Length) + while ((uint)dstIndex < (uint)zd.Length) // is equivalent to (dstIndex >= 0 && dstIndex < zd.Length) { uint part = xd[srcIndex]; zd[dstIndex] = (part >> smallShift) | carry; carry = part << carryShift; - dstIndex++; - srcIndex++; + dstIndex--; + srcIndex--; } } @@ -5232,13 +5264,32 @@ static bool INumberBase.TryConvertToTruncating(BigInteger va BigInteger result; + bool negx = value._sign < 0; + uint smallBits = NumericsHelpers.Abs(value._sign); + scoped ReadOnlySpan bits = value._bits; + if (bits.IsEmpty) + { + bits = new ReadOnlySpan(in smallBits); + } + + int xl = bits.Length; + if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1))) + { + // For a shift of N x 32 bit, + // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion. + // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00] + // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back. + // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back + // If the 2's component's last element is a 0, we will track the sign externally + ++xl; + } + uint[]? xdFromPool = null; - int xl = value._bits?.Length ?? 1; Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); - - bool negx = value.GetPartsForBitManipulation(xd); + xd[^1] = 0; + bits.CopyTo(xd); if (negx) { diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/MyBigInt.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/MyBigInt.cs index 58d4afdc819f71..2646d85e8df501 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/MyBigInt.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/MyBigInt.cs @@ -108,8 +108,14 @@ public static BigInteger DoBinaryOperatorMine(BigInteger num1, BigInteger num2, return new BigInteger(Max(bytes1, bytes2).ToArray()); case "b>>": return new BigInteger(ShiftLeft(bytes1, Negate(bytes2)).ToArray()); + case "b>>>": + return new BigInteger(ShiftRightUnsigned(bytes1, bytes2).ToArray()); case "b<<": return new BigInteger(ShiftLeft(bytes1, bytes2).ToArray()); + case "bRotateLeft": + return new BigInteger(RotateLeft(bytes1, bytes2).ToArray()); + case "bRotateRight": + return new BigInteger(RotateLeft(bytes1, Negate(bytes2)).ToArray()); case "b^": return new BigInteger(Xor(bytes1, bytes2).ToArray()); case "b|": @@ -637,11 +643,68 @@ public static List Not(List bytes) return bnew; } + public static List ShiftRightUnsigned(List bytes1, List bytes2) + { + int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List(new byte[] { 8 })).ToArray()); + sbyte bitShift = (sbyte)new BigInteger(Remainder(Copy(bytes2), new List(new byte[] { 8 })).ToArray()); + + if (byteShift == 0 && bitShift == 0) + return bytes1; + + if (byteShift < 0 || bitShift < 0) + return ShiftLeft(bytes1, Negate(bytes2)); + + Trim(bytes1); + + byte fill = (bytes1[bytes1.Count - 1] & 0x80) != 0 ? byte.MaxValue : (byte)0; + + if (fill == byte.MaxValue) + { + while (bytes1.Count % 4 != 0) + { + bytes1.Add(fill); + } + } + + if (byteShift >= bytes1.Count) + { + return [fill]; + } + + if (fill == byte.MaxValue) + { + bytes1.Add(0); + } + + for (int i = 0; i < bitShift; i++) + { + bytes1 = ShiftRight(bytes1); + } + + List temp = new List(); + for (int i = byteShift; i < bytes1.Count; i++) + { + temp.Add(bytes1[i]); + } + bytes1 = temp; + + if (fill == byte.MaxValue && bytes1.Count % 4 == 1) + { + bytes1.RemoveAt(bytes1.Count - 1); + } + + Trim(bytes1); + + return bytes1; + } + public static List ShiftLeft(List bytes1, List bytes2) { int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List(new byte[] { 8 })).ToArray()); sbyte bitShift = (sbyte)new BigInteger(Remainder(bytes2, new List(new byte[] { 8 })).ToArray()); + Trim(bytes1); + for (int i = 0; i < Math.Abs(bitShift); i++) { if (bitShift < 0) @@ -774,6 +837,105 @@ public static List ShiftRight(List bytes) return bresult; } + public static List RotateRight(List bytes) + { + List bresult = new List(); + + byte bottom = (byte)(bytes[0] & 0x01); + + for (int i = 0; i < bytes.Count; i++) + { + byte newbyte = bytes[i]; + + newbyte = (byte)(newbyte / 2); + if ((i != (bytes.Count - 1)) && ((bytes[i + 1] & 0x01) == 1)) + { + newbyte += 128; + } + if ((i == (bytes.Count - 1)) && (bottom != 0)) + { + newbyte += 128; + } + bresult.Add(newbyte); + } + + return bresult; + } + + public static List RotateLeft(List bytes) + { + List bresult = new List(); + + bool prevHead = (bytes[bytes.Count - 1] & 0x80) != 0; + + for (int i = 0; i < bytes.Count; i++) + { + byte newbyte = bytes[i]; + + newbyte = (byte)(newbyte * 2); + if (prevHead) + { + newbyte += 1; + } + + bresult.Add(newbyte); + + prevHead = (bytes[i] & 0x80) != 0; + } + + return bresult; + } + + + public static List RotateLeft(List bytes1, List bytes2) + { + List bytes1Copy = Copy(bytes1); + int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List(new byte[] { 8 })).ToArray()); + sbyte bitShift = (sbyte)new BigInteger(Remainder(bytes2, new List(new byte[] { 8 })).ToArray()); + + Trim(bytes1); + + byte fill = (bytes1[bytes1.Count - 1] & 0x80) != 0 ? byte.MaxValue : (byte)0; + + if (fill == 0 && bytes1.Count > 1 && bytes1[bytes1.Count - 1] == 0) + bytes1.RemoveAt(bytes1.Count - 1); + + while (bytes1.Count % 4 != 0) + { + bytes1.Add(fill); + } + + byteShift %= bytes1.Count; + if (byteShift == 0 && bitShift == 0) + return bytes1Copy; + + for (int i = 0; i < Math.Abs(bitShift); i++) + { + if (bitShift < 0) + { + bytes1 = RotateRight(bytes1); + } + else + { + bytes1 = RotateLeft(bytes1); + } + } + + List temp = new List(); + for (int i = 0; i < bytes1.Count; i++) + { + temp.Add(bytes1[(i - byteShift + bytes1.Count) % bytes1.Count]); + } + bytes1 = temp; + + if (fill == 0) + bytes1.Add(0); + + Trim(bytes1); + + return bytes1; + } + public static List SetLength(List bytes, int size) { List bresult = new List(); diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs new file mode 100644 index 00000000000000..564eb23935cda9 --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs @@ -0,0 +1,629 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using Xunit; + +namespace System.Numerics.Tests +{ + public abstract class RotateTestBase + { + public abstract string opstring { get; } + private static int s_samples = 10; + private static Random s_random = new Random(100); + + [Fact] + public void RunRotateTests() + { + byte[] tempByteArray1; + byte[] tempByteArray2; + + // Rotate Method - Large BigIntegers - large + Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = GetRandomPosByteArray(s_random, 2); + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - small + Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - 32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = new byte[] { (byte)32 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - All One Uint Large BigIntegers - 32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random); + tempByteArray2 = new byte[] { (byte)32 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Uint 0xffffffff 0x8000000 ... Large BigIntegers - 32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(s_random); + tempByteArray2 = new byte[] { (byte)32 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - large - Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = GetRandomNegByteArray(s_random, 2); + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - small - Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - -32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = new byte[] { (byte)0xe0 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Large BigIntegers - 0 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random); + tempByteArray2 = new byte[] { (byte)0 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - large + Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = GetRandomPosByteArray(s_random, 2); + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - small + Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - 32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = new byte[] { (byte)32 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + // Rotate Method - Small BigIntegers - large - Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = GetRandomNegByteArray(s_random, 2); + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - small - Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - -32 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = new byte[] { (byte)0xe0 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Small BigIntegers - 0 bit Shift + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomByteArray(s_random, 2); + tempByteArray2 = new byte[] { (byte)0 }; + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Positive BigIntegers - Shift to 0 + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomPosByteArray(s_random, 100); + tempByteArray2 = BitConverter.GetBytes(s_random.Next(8 * tempByteArray1.Length, 1000)); + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(tempByteArray2); + } + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + + // Rotate Method - Negative BigIntegers - Shift to -1 + for (int i = 0; i < s_samples; i++) + { + tempByteArray1 = GetRandomNegByteArray(s_random, 100); + tempByteArray2 = BitConverter.GetBytes(s_random.Next(8 * tempByteArray1.Length, 1000)); + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(tempByteArray2); + } + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + } + + [Fact] + public void RunSmallTests() + { + foreach (int i in new int[] { + 0, + 1, + 16, + 31, + 32, + 33, + 63, + 64, + 65, + 100, + 127, + 128, + }) + { + foreach (int shift in new int[] { + 0, + -1, 1, + -16, 16, + -31, 31, + -32, 32, + -33, 33, + -63, 63, + -64, 64, + -65, 65, + -100, 100, + -127, 127, + -128, 128, + }) + { + var num = Int128.One << i; + for (int k = -1; k <= 1; k++) + { + foreach (int sign in new int[] { -1, +1 }) + { + Int128 value128 = sign * (num + k); + + byte[] tempByteArray1 = GetRandomSmallByteArray(value128); + byte[] tempByteArray2 = GetRandomSmallByteArray(shift); + + VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + } + } + } + } + + private static void VerifyRotateString(string opstring) + { + StackCalc sc = new StackCalc(opstring); + while (sc.DoNextOperation()) + { + Assert.Equal(sc.snCalc.Peek().ToString(), sc.myCalc.Peek().ToString()); + } + } + + private static byte[] GetRandomSmallByteArray(Int128 num) + { + byte[] value = new byte[16]; + + for (int i = 0; i < value.Length; i++) + { + value[i] = (byte)num; + num >>= 8; + } + + return value; + } + + private static byte[] GetRandomByteArray(Random random) + { + return GetRandomByteArray(random, random.Next(0, 1024)); + } + + private static byte[] GetRandomByteArray(Random random, int size) + { + return MyBigIntImp.GetRandomByteArray(random, size); + } + + private static byte[] GetRandomPosByteArray(Random random, int size) + { + byte[] value = new byte[size]; + + for (int i = 0; i < value.Length; ++i) + { + value[i] = (byte)random.Next(0, 256); + } + value[value.Length - 1] &= 0x7F; + + return value; + } + + private static byte[] GetRandomNegByteArray(Random random, int size) + { + byte[] value = new byte[size]; + + for (int i = 0; i < value.Length; ++i) + { + value[i] = (byte)random.Next(0, 256); + } + value[value.Length - 1] |= 0x80; + + return value; + } + + private static byte[] GetRandomLengthAllOnesUIntByteArray(Random random) + { + int gap = random.Next(0, 128); + int byteLength = 4 + gap * 4 + 1; + byte[] array = new byte[byteLength]; + array[0] = 1; + array[^1] = 0xFF; + return array; + } + private static byte[] GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(Random random) + { + int gap = random.Next(0, 128); + int byteLength = 4 + gap * 4 + 1; + byte[] array = new byte[byteLength]; + array[^5] = 0x80; + array[^1] = 0xFF; + return array; + } + + private static string Print(byte[] bytes) + { + return MyBigIntImp.Print(bytes); + } + } + + public class RotateLeftTest : RotateTestBase + { + public override string opstring => "bRotateLeft"; + + + public static TheoryData NegativeNumber_TestData = new TheoryData + { + + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)), + 1, + new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0001)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)), + 2, + new BigInteger(unchecked((long)0xFFFF_FFFC_0000_0003)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)), + 1, + new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0003)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)), + 2, + new BigInteger(unchecked((long)0xFFFF_FFFC_0000_0007)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)), + 1, + new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0005)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)), + 2, + new BigInteger(unchecked((long)0xFFFF_FFFC_0000_000B)) + }, + + { + new BigInteger(unchecked((long)0x8000_0000_0000_0000)), + 1, + new BigInteger(0x1) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0000)), + 2, + new BigInteger(0x2) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0001)), + 1, + new BigInteger(0x3) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0001)), + 2, + new BigInteger(0x6) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0002)), + 1, + new BigInteger(0x5) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0002)), + 2, + new BigInteger(0xA) + }, + + { + BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 1, + new BigInteger(0x1) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 2, + new BigInteger(0x2) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 1, + new BigInteger(0x3) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 2, + new BigInteger(0x6) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 1, + new BigInteger(0x5) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 2, + new BigInteger(0xA) + }, + + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("________E_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("________C_0000_0000_0000_0000_0000_0003".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("________E_0000_0000_0000_0000_0000_0003".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("________C_0000_0000_0000_0000_0000_0007".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("________E_0000_0000_0000_0000_0000_0005".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("________C_0000_0000_0000_0000_0000_000B".Replace("_", ""), NumberStyles.HexNumber) + }, + }; + + [Theory] + [MemberData(nameof(NegativeNumber_TestData))] + public void NegativeNumber(BigInteger input, int rotateAmount, BigInteger expected) + { + Assert.Equal(expected, BigInteger.RotateLeft(input, rotateAmount)); + } + + [Fact] + public void PowerOfTwo() + { + for (int i = 0; i < 32; i++) + { + foreach (int k in new int[] { 1, 2, 3, 10 }) + { + BigInteger plus = BigInteger.One << (32 * k + i); + BigInteger minus = BigInteger.MinusOne << (32 * k + i); + + Assert.Equal(BigInteger.One << (i == 31 ? 0 : (32 * k + i + 1)), BigInteger.RotateLeft(plus, 1)); + Assert.Equal(BigInteger.One << i, BigInteger.RotateLeft(plus, 32)); + Assert.Equal(BigInteger.One << (32 * (k - 1) + i), BigInteger.RotateLeft(plus, 32 * k)); + + Assert.Equal(i == 31 ? BigInteger.One : (new BigInteger(-1 << (i + 1)) << 32 * k) + 1, + BigInteger.RotateLeft(minus, 1)); + Assert.Equal(new BigInteger(uint.MaxValue << i), BigInteger.RotateLeft(minus, 32)); + Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * (k - 1)), BigInteger.RotateLeft(minus, 32 * k)); + } + } + } + } + + public class RotateRightTest : RotateTestBase + { + public override string opstring => "bRotateRight"; + + public static TheoryData NegativeNumber_TestData = new TheoryData + { + + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)), + 1, + new BigInteger(unchecked((long)0x7FFF_FFFF_8000_0000)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)), + 2, + new BigInteger(unchecked((long)0x3FFF_FFFF_C000_0000)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)), + 1, + new BigInteger(unchecked((int)0x8000_0000)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)), + 2, + new BigInteger(unchecked((long)0x7FFF_FFFF_C000_0000)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)), + 1, + new BigInteger(unchecked((long)0x7FFF_FFFF_8000_0001)) + }, + { + new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)), + 2, + new BigInteger(unchecked((long)0xBFFF_FFFF_C000_0000)) + }, + + { + new BigInteger(unchecked((long)0x8000_0000_0000_0000)), + 1, + new BigInteger(unchecked((long)0x4000_0000_0000_0000)) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0000)), + 2, + new BigInteger(unchecked((long)0x2000_0000_0000_0000)) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0001)), + 1, + new BigInteger(unchecked((long)0xC000_0000_0000_0000)) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0001)), + 2, + new BigInteger(unchecked((long)0x6000_0000_0000_0000)) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0002)), + 1, + new BigInteger(unchecked((long)0x4000_0000_0000_0001)) + }, + { + new BigInteger(unchecked((long)0x8000_0000_0000_0002)), + 2, + new BigInteger(unchecked((long)0xA000_0000_0000_0000)) + }, + + { + BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("4000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("2000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("6000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("4000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("A000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("7FFF_FFFF_8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("3FFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("__________8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("7FFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 1, + BigInteger.Parse("7FFF_FFFF_8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber) + }, + { + BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber), + 2, + BigInteger.Parse("BFFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber) + }, + }; + + [Theory] + [MemberData(nameof(NegativeNumber_TestData))] + public void NegativeNumber(BigInteger input, int rotateAmount, BigInteger expected) + { + Assert.Equal(expected, BigInteger.RotateRight(input, rotateAmount)); + } + + [Fact] + public void PowerOfTwo() + { + for (int i = 0; i < 32; i++) + { + foreach (int k in new int[] { 1, 2, 3, 10 }) + { + BigInteger plus = BigInteger.One << (32 * k + i); + BigInteger minus = BigInteger.MinusOne << (32 * k + i); + + Assert.Equal(BigInteger.One << (32 * k + i - 1), BigInteger.RotateRight(plus, 1)); + Assert.Equal(BigInteger.One << (32 * (k - 1) + i), BigInteger.RotateRight(plus, 32)); + Assert.Equal(BigInteger.One << i, BigInteger.RotateRight(plus, 32 * k)); + + Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * k - 1), BigInteger.RotateRight(minus, 1)); + Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * (k - 1)), BigInteger.RotateRight(minus, 32)); + Assert.Equal(new BigInteger(uint.MaxValue << i), BigInteger.RotateRight(minus, 32 * k)); + } + } + } + } +} diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_leftshift.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_leftshift.cs index 47b0a8ea7678cd..6c278bb63edb6e 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_leftshift.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_leftshift.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using Xunit; namespace System.Numerics.Tests @@ -151,6 +152,56 @@ public static void RunLeftShiftTests() } } + [Fact] + public void RunSmallTests() + { + foreach (int i in new int[] { + 0, + 1, + 16, + 31, + 32, + 33, + 63, + 64, + 65, + 100, + 127, + 128, + }) + { + foreach (int shift in new int[] { + 0, + -1, 1, + -16, 16, + -31, 31, + -32, 32, + -33, 33, + -63, 63, + -64, 64, + -65, 65, + -100, 100, + -127, 127, + -128, 128, + }) + { + var num = Int128.One << i; + for (int k = -1; k <= 1; k++) + { + foreach (int sign in new int[] { -1, +1 }) + { + Int128 value128 = sign * (num + k); + + byte[] tempByteArray1 = GetRandomSmallByteArray(value128); + byte[] tempByteArray2 = GetRandomSmallByteArray(shift); + + VerifyLeftShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b<<"); + } + } + } + } + } + private static void VerifyLeftShiftString(string opstring) { StackCalc sc = new StackCalc(opstring); @@ -160,6 +211,19 @@ private static void VerifyLeftShiftString(string opstring) } } + private static byte[] GetRandomSmallByteArray(Int128 num) + { + byte[] value = new byte[16]; + + for (int i = 0; i < value.Length; i++) + { + value[i] = (byte)num; + num >>= 8; + } + + return value; + } + private static byte[] GetRandomByteArray(Random random) { return GetRandomByteArray(random, random.Next(0, 1024)); diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs index 404902f61972e7..c725d52bc0ba4c 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs @@ -1,92 +1,29 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using Xunit; namespace System.Numerics.Tests { - public class op_rightshiftTest + public abstract class op_rightshiftTestBase { + public abstract string opstring { get; } private static int s_samples = 10; private static Random s_random = new Random(100); [Fact] - public static void BigShiftsTest() - { - BigInteger a = new BigInteger(1); - BigInteger b = new BigInteger(Math.Pow(2, 31)); - - for (int i = 0; i < 100; i++) - { - BigInteger a1 = (a << (i + 31)); - BigInteger a2 = a1 >> i; - - Assert.Equal(b, a2); - } - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] // May fail on 32-bit due to a large memory requirement - public static void LargeNegativeBigIntegerShiftTest() + public void RunRightShiftTests() { - // Create a very large negative BigInteger - int bitsPerElement = 8 * sizeof(uint); - int maxBitLength = ((Array.MaxLength / bitsPerElement) * bitsPerElement); - BigInteger bigInt = new BigInteger(-1) << (maxBitLength - 1); - Assert.Equal(maxBitLength - 1, bigInt.GetBitLength()); - Assert.Equal(-1, bigInt.Sign); - - // Validate internal representation. - // At this point, bigInt should be a 1 followed by maxBitLength - 1 zeros. - // Given this, bigInt._bits is expected to be structured as follows: - // - _bits.Length == ceil(maxBitLength / bitsPerElement) - // - First (_bits.Length - 1) elements: 0x00000000 - // - Last element: 0x80000000 - // ^------ (There's the leading '1') - - Assert.Equal((maxBitLength + (bitsPerElement - 1)) / bitsPerElement, bigInt._bits.Length); - - uint i = 0; - for (; i < (bigInt._bits.Length - 1); i++) { - Assert.Equal(0x00000000u, bigInt._bits[i]); - } - - Assert.Equal(0x80000000u, bigInt._bits[i]); - - // Right shift the BigInteger - BigInteger shiftedBigInt = bigInt >> 1; - Assert.Equal(maxBitLength - 2, shiftedBigInt.GetBitLength()); - Assert.Equal(-1, shiftedBigInt.Sign); - - // Validate internal representation. - // At this point, shiftedBigInt should be a 1 followed by maxBitLength - 2 zeros. - // Given this, shiftedBigInt._bits is expected to be structured as follows: - // - _bits.Length == ceil((maxBitLength - 1) / bitsPerElement) - // - First (_bits.Length - 1) elements: 0x00000000 - // - Last element: 0x40000000 - // ^------ (the '1' is now one position to the right) - - Assert.Equal(((maxBitLength - 1) + (bitsPerElement - 1)) / bitsPerElement, shiftedBigInt._bits.Length); - - i = 0; - for (; i < (shiftedBigInt._bits.Length - 1); i++) { - Assert.Equal(0x00000000u, shiftedBigInt._bits[i]); - } - - Assert.Equal(0x40000000u, shiftedBigInt._bits[i]); - } - - [Fact] - public static void RunRightShiftTests() - { - byte[] tempByteArray1 = new byte[0]; - byte[] tempByteArray2 = new byte[0]; + byte[] tempByteArray1; + byte[] tempByteArray2; // RightShift Method - Large BigIntegers - large + Shift for (int i = 0; i < s_samples; i++) { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = GetRandomPosByteArray(s_random, 2); - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - small + Shift @@ -94,7 +31,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - 32 bit Shift @@ -102,7 +39,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = new byte[] { (byte)32 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - All One Uint Large BigIntegers - 32 bit Shift @@ -110,7 +47,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random); tempByteArray2 = new byte[] { (byte)32 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Uint 0xffffffff 0x8000000 ... Large BigIntegers - 32 bit Shift @@ -118,7 +55,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(s_random); tempByteArray2 = new byte[] { (byte)32 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - large - Shift @@ -126,7 +63,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = GetRandomNegByteArray(s_random, 2); - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - small - Shift @@ -134,7 +71,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - -32 bit Shift @@ -142,7 +79,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = new byte[] { (byte)0xe0 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Large BigIntegers - 0 bit Shift @@ -150,7 +87,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random); tempByteArray2 = new byte[] { (byte)0 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - large + Shift @@ -158,7 +95,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = GetRandomPosByteArray(s_random, 2); - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - small + Shift @@ -166,7 +103,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - 32 bit Shift @@ -174,14 +111,14 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = new byte[] { (byte)32 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - large - Shift for (int i = 0; i < s_samples; i++) { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = GetRandomNegByteArray(s_random, 2); - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - small - Shift @@ -189,7 +126,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - -32 bit Shift @@ -197,7 +134,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = new byte[] { (byte)0xe0 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Small BigIntegers - 0 bit Shift @@ -205,7 +142,7 @@ public static void RunRightShiftTests() { tempByteArray1 = GetRandomByteArray(s_random, 2); tempByteArray2 = new byte[] { (byte)0 }; - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Positive BigIntegers - Shift to 0 @@ -217,7 +154,7 @@ public static void RunRightShiftTests() { Array.Reverse(tempByteArray2); } - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); } // RightShift Method - Negative BigIntegers - Shift to -1 @@ -229,7 +166,57 @@ public static void RunRightShiftTests() { Array.Reverse(tempByteArray2); } - VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>"); + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + } + + [Fact] + public void RunSmallTests() + { + foreach (int i in new int[] { + 0, + 1, + 16, + 31, + 32, + 33, + 63, + 64, + 65, + 100, + 127, + 128, + }) + { + foreach (int shift in new int[] { + 0, + -1, 1, + -16, 16, + -31, 31, + -32, 32, + -33, 33, + -63, 63, + -64, 64, + -65, 65, + -100, 100, + -127, 127, + -128, 128, + }) + { + var num = Int128.One << i; + for (int k = -1; k <= 1; k++) + { + foreach (int sign in new int[] { -1, +1 }) + { + Int128 value128 = sign * (num + k); + + byte[] tempByteArray1 = GetRandomSmallByteArray(value128); + byte[] tempByteArray2 = GetRandomSmallByteArray(shift); + + VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring); + } + } + } } } @@ -242,6 +229,19 @@ private static void VerifyRightShiftString(string opstring) } } + private static byte[] GetRandomSmallByteArray(Int128 num) + { + byte[] value = new byte[16]; + + for (int i = 0; i < value.Length; i++) + { + value[i] = (byte)num; + num >>= 8; + } + + return value; + } + private static byte[] GetRandomByteArray(Random random) { return GetRandomByteArray(random, random.Next(0, 1024)); @@ -292,7 +292,7 @@ private static byte[] GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(Random ra int gap = random.Next(0, 128); int byteLength = 4 + gap * 4 + 1; byte[] array = new byte[byteLength]; - array[^6] = 0x80; + array[^5] = 0x80; array[^1] = 0xFF; return array; } @@ -302,4 +302,93 @@ private static string Print(byte[] bytes) return MyBigIntImp.Print(bytes); } } + public class op_rightshiftTest : op_rightshiftTestBase + { + public override string opstring => "b>>"; + + [Fact] + public static void BigShiftsTest() + { + BigInteger a = new BigInteger(1); + BigInteger b = new BigInteger(Math.Pow(2, 31)); + + for (int i = 0; i < 100; i++) + { + BigInteger a1 = (a << (i + 31)); + BigInteger a2 = a1 >> i; + + Assert.Equal(b, a2); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] // May fail on 32-bit due to a large memory requirement + public static void LargeNegativeBigIntegerShiftTest() + { + // Create a very large negative BigInteger + int bitsPerElement = 8 * sizeof(uint); + int maxBitLength = ((Array.MaxLength / bitsPerElement) * bitsPerElement); + BigInteger bigInt = new BigInteger(-1) << (maxBitLength - 1); + Assert.Equal(maxBitLength - 1, bigInt.GetBitLength()); + Assert.Equal(-1, bigInt.Sign); + + // Validate internal representation. + // At this point, bigInt should be a 1 followed by maxBitLength - 1 zeros. + // Given this, bigInt._bits is expected to be structured as follows: + // - _bits.Length == ceil(maxBitLength / bitsPerElement) + // - First (_bits.Length - 1) elements: 0x00000000 + // - Last element: 0x80000000 + // ^------ (There's the leading '1') + + Assert.Equal((maxBitLength + (bitsPerElement - 1)) / bitsPerElement, bigInt._bits.Length); + + uint i = 0; + for (; i < (bigInt._bits.Length - 1); i++) + { + Assert.Equal(0x00000000u, bigInt._bits[i]); + } + + Assert.Equal(0x80000000u, bigInt._bits[i]); + + // Right shift the BigInteger + BigInteger shiftedBigInt = bigInt >> 1; + Assert.Equal(maxBitLength - 2, shiftedBigInt.GetBitLength()); + Assert.Equal(-1, shiftedBigInt.Sign); + + // Validate internal representation. + // At this point, shiftedBigInt should be a 1 followed by maxBitLength - 2 zeros. + // Given this, shiftedBigInt._bits is expected to be structured as follows: + // - _bits.Length == ceil((maxBitLength - 1) / bitsPerElement) + // - First (_bits.Length - 1) elements: 0x00000000 + // - Last element: 0x40000000 + // ^------ (the '1' is now one position to the right) + + Assert.Equal(((maxBitLength - 1) + (bitsPerElement - 1)) / bitsPerElement, shiftedBigInt._bits.Length); + + i = 0; + for (; i < (shiftedBigInt._bits.Length - 1); i++) + { + Assert.Equal(0x00000000u, shiftedBigInt._bits[i]); + } + + Assert.Equal(0x40000000u, shiftedBigInt._bits[i]); + } + } + + public class op_UnsignedRightshiftTest : op_rightshiftTestBase + { + public override string opstring => "b>>>"; + + [Fact] + public void PowerOfTwo() + { + for (int i = 0; i < 32; i++) + { + foreach (int k in new int[] { 1, 2, 10 }) + { + Assert.Equal(BigInteger.One << i, (BigInteger.One << (32 * k + i)) >>> (32 * k)); + Assert.Equal(new BigInteger(unchecked((int)(uint.MaxValue << i))), (BigInteger.MinusOne << (32 * k + i)) >>> (32 * k)); + } + } + } + } } diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/stackcalculator.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/stackcalculator.cs index c53e87a15a234f..cbd2a04127ef7f 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/stackcalculator.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/stackcalculator.cs @@ -191,8 +191,14 @@ private BigInteger DoBinaryOperatorSN(BigInteger num1, BigInteger num2, string o return BigInteger.Max(num1, num2); case "b>>": return num1 >> (int)num2; + case "b>>>": + return num1 >>> (int)num2; case "b<<": return num1 << (int)num2; + case "bRotateLeft": + return BigInteger.RotateLeft(num1, (int)num2); + case "bRotateRight": + return BigInteger.RotateRight(num1, (int)num2); case "b^": return num1 ^ num2; case "b|": @@ -254,7 +260,7 @@ public void VerifyOutParameter() private static string Print(byte[] bytes) { - return MyBigIntImp.PrintFormatX(bytes); + return MyBigIntImp.PrintFormatX(bytes); } } } diff --git a/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj b/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj index 4224f0ac83414f..5d468f9ce66885 100644 --- a/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj +++ b/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj @@ -42,6 +42,7 @@ + From b46e5a22cbdbd8d2059eb3ceeafee54d354947b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 15:22:21 -0400 Subject: [PATCH 35/39] [release/9.0-staging] [mono] Switch generic instance cache back to GHashTable; improve ginst hash function (#113316) Backport of https://github.com/dotnet/runtime/pull/113287 This change will revert to the hashtable container used for the generic instance cache in .NET 8.0 to address a performance regression introduced by changing to a different container in 9. Also improves the hash function used for the cache (the existing one was suboptimal.) Co-authored-by: Katelyn Gadd --- src/mono/mono/metadata/loader-internals.h | 3 ++- src/mono/mono/metadata/memory-manager.c | 2 +- src/mono/mono/metadata/metadata.c | 19 +++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/metadata/loader-internals.h b/src/mono/mono/metadata/loader-internals.h index 60d39ff6a6398c..c9a340f928b7b2 100644 --- a/src/mono/mono/metadata/loader-internals.h +++ b/src/mono/mono/metadata/loader-internals.h @@ -175,7 +175,8 @@ struct _MonoMemoryManager { MonoAssemblyLoadContext **alcs; // Generic-specific caches - dn_simdhash_ght_t *ginst_cache, *gmethod_cache, *gsignature_cache; + GHashTable *ginst_cache; + dn_simdhash_ght_t *gmethod_cache, *gsignature_cache; MonoConcurrentHashTable *gclass_cache; /* mirror caches of ones already on MonoImage. These ones contain generics */ diff --git a/src/mono/mono/metadata/memory-manager.c b/src/mono/mono/metadata/memory-manager.c index edb7fff24a8d3c..e7a234661db5a3 100644 --- a/src/mono/mono/metadata/memory-manager.c +++ b/src/mono/mono/metadata/memory-manager.c @@ -238,7 +238,7 @@ memory_manager_delete (MonoMemoryManager *memory_manager, gboolean debug_unload) MonoMemoryManager *mm = memory_manager; if (mm->gclass_cache) mono_conc_hashtable_destroy (mm->gclass_cache); - free_simdhash (&mm->ginst_cache); + free_hash (&mm->ginst_cache); free_simdhash (&mm->gmethod_cache); free_simdhash (&mm->gsignature_cache); free_hash (&mm->szarray_cache); diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 91da538ff585a6..8a96c1ead4c337 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -38,6 +38,7 @@ #include #include #include +#include "../native/containers/dn-simdhash-utils.h" /* Auxiliary structure used for caching inflated signatures */ typedef struct { @@ -1874,18 +1875,21 @@ mono_type_equal (gconstpointer ka, gconstpointer kb) guint mono_metadata_generic_inst_hash (gconstpointer data) { + // Custom MurmurHash3 for generic instances to produce a high quality hash const MonoGenericInst *ginst = (const MonoGenericInst *) data; - guint hash = 0; g_assert (ginst); g_assert (ginst->type_argv); + uint32_t h1 = ginst->type_argc; + for (guint i = 0; i < ginst->type_argc; ++i) { - hash *= 13; g_assert (ginst->type_argv [i]); - hash += mono_metadata_type_hash (ginst->type_argv [i]); + MURMUR3_HASH_BLOCK ((uint32_t) mono_metadata_type_hash (ginst->type_argv [i])); } - return hash ^ (ginst->is_open << 8); + h1 ^= ginst->is_open; + + return (guint)murmur3_fmix32 (h1); } static gboolean @@ -3494,10 +3498,9 @@ mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate) mono_loader_lock (); if (!mm->ginst_cache) - mm->ginst_cache = dn_simdhash_ght_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst, 0, NULL); + mm->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); - MonoGenericInst *ginst = NULL; - dn_simdhash_ght_try_get_value (mm->ginst_cache, candidate, (void **)&ginst); + MonoGenericInst *ginst = g_hash_table_lookup (mm->ginst_cache, candidate); if (!ginst) { int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *); ginst = (MonoGenericInst *)mono_mem_manager_alloc0 (mm, size); @@ -3511,7 +3514,7 @@ mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate) for (int i = 0; i < type_argc; ++i) ginst->type_argv [i] = mono_metadata_type_dup (NULL, candidate->type_argv [i]); - dn_simdhash_ght_insert (mm->ginst_cache, ginst, ginst); + g_hash_table_insert (mm->ginst_cache, ginst, ginst); } mono_loader_unlock (); From 34e3ff2c2842e57c1f3542514425da0daa27af21 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 16:09:29 -0700 Subject: [PATCH 36/39] Update dependencies from https://github.com/dotnet/sdk build 20250211.36 (#112628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microsoft.SourceBuild.Intermediate.sdk , Microsoft.DotNet.ApiCompat.Task From Version 9.0.103-servicing.25065.25 -> To Version 9.0.104-servicing.25111.36 Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- NuGet.config | 1 + eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/NuGet.config b/NuGet.config index 937f423c99ca1e..4f9535f38d69ea 100644 --- a/NuGet.config +++ b/NuGet.config @@ -12,6 +12,7 @@ + - + https://github.com/dotnet/sdk - 049799c39d766c58ef6388865d5f5ed273b6a75e + 346d06baea1cf7113e181e779b056b955973c633 diff --git a/eng/Versions.props b/eng/Versions.props index f53f489e44824b..3775693e357602 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -83,7 +83,7 @@ 0.2.0 - 9.0.103 + 9.0.104 9.0.0-beta.25111.5 9.0.0-beta.25111.5 From 6758abdc170014dd7f022d417fe1a3890873cb7b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:23:30 +0100 Subject: [PATCH 37/39] [release/9.0-staging] Fix HttpHandlerDiagnosticListenerTests.TestW3CHeadersTraceStateAndCorrelationContext (#112882) Backport of #112753 to release/9.0-staging --- .../tests/HttpHandlerDiagnosticListenerTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs index 0c23059c17ae88..ecfe219e072843 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/HttpHandlerDiagnosticListenerTests.cs @@ -145,6 +145,7 @@ public async Task TestBasicReceiveAndResponseEvents() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/112792")] [OuterLoop] [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void TestW3CHeaders() @@ -194,6 +195,7 @@ public void TestW3CHeadersTraceStateAndCorrelationContext() { using (var eventRecords = new EventObserverAndRecorder()) { + Activity.DefaultIdFormat = ActivityIdFormat.W3C; var parent = new Activity("w3c activity"); parent.SetParentId(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom()); parent.TraceStateString = "some=state"; From 111a76e4af52344d536339a2a62314a56b1a1a43 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 12 Mar 2025 22:26:17 +0000 Subject: [PATCH 38/39] Update dependencies from https://github.com/dotnet/arcade build 20250311.4 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.25111.5 -> To Version 9.0.0-beta.25161.4 --- NuGet.config | 1 - eng/Version.Details.xml | 84 +++++++++---------- eng/Versions.props | 32 +++---- .../core-templates/steps/generate-sbom.yml | 2 +- eng/common/generate-sbom-prep.ps1 | 20 +++-- eng/common/generate-sbom-prep.sh | 17 ++-- eng/common/templates-official/job/job.yml | 1 + global.json | 10 +-- 8 files changed, 90 insertions(+), 77 deletions(-) diff --git a/NuGet.config b/NuGet.config index 9d44e25da71a31..deafa2a01414c9 100644 --- a/NuGet.config +++ b/NuGet.config @@ -10,7 +10,6 @@ - diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index af2296e50d4fed..5417063b3d3b6b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -92,87 +92,87 @@ - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 https://github.com/dotnet/runtime-assets @@ -332,9 +332,9 @@ https://github.com/dotnet/xharness edc52ac68c1bf77e3b107fc8a448674a6d058d8a - + https://github.com/dotnet/arcade - 5da211e1c42254cb35e7ef3d5a8428fb24853169 + f33d9e642f0e68a61312164cd9e0baf4e142a999 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 529914efb810e3..8ba353723841c2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,22 +85,22 @@ 9.0.104 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 2.9.0-beta.25111.5 - 9.0.0-beta.25111.5 - 2.9.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 - 9.0.0-beta.25111.5 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 2.9.0-beta.25161.4 + 9.0.0-beta.25161.4 + 2.9.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 + 9.0.0-beta.25161.4 1.4.0 diff --git a/eng/common/core-templates/steps/generate-sbom.yml b/eng/common/core-templates/steps/generate-sbom.yml index d938b60e1bb534..56a090094824f4 100644 --- a/eng/common/core-templates/steps/generate-sbom.yml +++ b/eng/common/core-templates/steps/generate-sbom.yml @@ -38,7 +38,7 @@ steps: PackageName: ${{ parameters.packageName }} BuildDropPath: ${{ parameters.buildDropPath }} PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} + ManifestDirPath: ${{ parameters.manifestDirPath }}/$(ARTIFACT_NAME) ${{ if ne(parameters.IgnoreDirectories, '') }}: AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' diff --git a/eng/common/generate-sbom-prep.ps1 b/eng/common/generate-sbom-prep.ps1 index 3e5c1c74a1c50d..a0c7d792a76fbe 100644 --- a/eng/common/generate-sbom-prep.ps1 +++ b/eng/common/generate-sbom-prep.ps1 @@ -4,18 +4,26 @@ Param( . $PSScriptRoot\pipeline-logging-functions.ps1 +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +$ArtifactName = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" +$SafeArtifactName = $ArtifactName -replace '["/:<>\\|?@*"() ]', '_' +$SbomGenerationDir = Join-Path $ManifestDirPath $SafeArtifactName + +Write-Host "Artifact name before : $ArtifactName" +Write-Host "Artifact name after : $SafeArtifactName" + Write-Host "Creating dir $ManifestDirPath" + # create directory for sbom manifest to be placed -if (!(Test-Path -path $ManifestDirPath)) +if (!(Test-Path -path $SbomGenerationDir)) { - New-Item -ItemType Directory -path $ManifestDirPath - Write-Host "Successfully created directory $ManifestDirPath" + New-Item -ItemType Directory -path $SbomGenerationDir + Write-Host "Successfully created directory $SbomGenerationDir" } else{ Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." } Write-Host "Updating artifact name" -$artifact_name = "${env:SYSTEM_STAGENAME}_${env:AGENT_JOBNAME}_SBOM" -replace '["/:<>\\|?@*"() ]', '_' -Write-Host "Artifact name $artifact_name" -Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$artifact_name" +Write-Host "##vso[task.setvariable variable=ARTIFACT_NAME]$SafeArtifactName" diff --git a/eng/common/generate-sbom-prep.sh b/eng/common/generate-sbom-prep.sh index d5c76dc827b496..b8ecca72bbf506 100644 --- a/eng/common/generate-sbom-prep.sh +++ b/eng/common/generate-sbom-prep.sh @@ -14,19 +14,24 @@ done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" . $scriptroot/pipeline-logging-functions.sh + +# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. +artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" +safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" manifest_dir=$1 -if [ ! -d "$manifest_dir" ] ; then - mkdir -p "$manifest_dir" - echo "Sbom directory created." $manifest_dir +# Normally - we'd listen to the manifest path given, but 1ES templates will overwrite if this level gets uploaded directly +# with their own overwriting ours. So we create it as a sub directory of the requested manifest path. +sbom_generation_dir="$manifest_dir/$safe_artifact_name" + +if [ ! -d "$sbom_generation_dir" ] ; then + mkdir -p "$sbom_generation_dir" + echo "Sbom directory created." $sbom_generation_dir else Write-PipelineTelemetryError -category 'Build' "Unable to create sbom folder." fi -artifact_name=$SYSTEM_STAGENAME"_"$AGENT_JOBNAME"_SBOM" echo "Artifact name before : "$artifact_name -# replace all special characters with _, some builds use special characters like : in Agent.Jobname, that is not a permissible name while uploading artifacts. -safe_artifact_name="${artifact_name//["/:<>\\|?@*$" ]/_}" echo "Artifact name after : "$safe_artifact_name export ARTIFACT_NAME=$safe_artifact_name echo "##vso[task.setvariable variable=ARTIFACT_NAME]$safe_artifact_name" diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml index 605692d2fb770c..817555505aa602 100644 --- a/eng/common/templates-official/job/job.yml +++ b/eng/common/templates-official/job/job.yml @@ -16,6 +16,7 @@ jobs: parameters: PackageVersion: ${{ parameters.packageVersion }} BuildDropPath: ${{ parameters.buildDropPath }} + ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom publishArtifacts: false # publish artifacts diff --git a/global.json b/global.json index 8cf149480ba5d3..ebf092e8e505d2 100644 --- a/global.json +++ b/global.json @@ -1,16 +1,16 @@ { "sdk": { - "version": "9.0.103", + "version": "9.0.104", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "9.0.103" + "dotnet": "9.0.104" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25111.5", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25111.5", - "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25111.5", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25161.4", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.25161.4", + "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.25161.4", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "9.0.0-rtm.24511.16" From d9d0ae01ab31513b02033317a9f716f1aeb5abab Mon Sep 17 00:00:00 2001 From: Haruna Ogweda Date: Thu, 13 Mar 2025 14:26:15 -0700 Subject: [PATCH 39/39] [release/9.0] fix SBOM issues for runtime (#113463) * update runtime repo to produce SBOM after signing artifacts * disable SBOM autogeneration for prepare signed artifacts leg * disable SBOM autogeneration for prepare signed artifacts leg * disable SBOM autogeneration for prepare signed artifacts leg * set the verbosity level of the logging output to Debug * remove unnecessary parameters * remove verbosity parameter * remove verbosity parameter * remove verbosity parameter --------- Co-authored-by: Haruna Ogweda --- eng/pipelines/official/jobs/prepare-signed-artifacts.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml index eb25d311890a98..482e2cc2b1e6f5 100644 --- a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml +++ b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml @@ -8,6 +8,9 @@ jobs: parameters: name: 'PrepareSignedArtifacts' displayName: 'Prepare Signed Artifacts' + + # Disable SBOM at job template level + enableSbom: false pool: name: $(DncEngInternalBuildPool) @@ -52,7 +55,11 @@ jobs: /p:DotNetSignType=$(_SignType) /bl:$(Build.SourcesDirectory)\prepare-artifacts.binlog displayName: Prepare artifacts and upload to build - + + - template: /eng/common/templates-official/steps/generate-sbom.yml + parameters: + BuildDropPath: $(Build.SourcesDirectory)\artifacts + - task: CopyFiles@2 displayName: Copy Files to $(Build.StagingDirectory)\BuildLogs inputs: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy