From 5c47007d2cbd6cacfa309670e0cb7cee78cebf91 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Tue, 24 Aug 2021 16:52:47 +0200 Subject: [PATCH 1/2] [mono] Use string.Empty for empty string custom arg values * Fixes https://github.com/dotnet/runtime/issues/58022 --- src/mono/mono/metadata/custom-attrs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/metadata/custom-attrs.c b/src/mono/mono/metadata/custom-attrs.c index 48571da6a085ea..29c64c48f3fafc 100644 --- a/src/mono/mono/metadata/custom-attrs.c +++ b/src/mono/mono/metadata/custom-attrs.c @@ -397,7 +397,11 @@ MONO_RESTORE_WARNING // to decode some attributes in assemblies that Windows .NET Framework // and CoreCLR both manage to decode. // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8. - *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (p, slen, error); + // Always use string.Empty for empty strings + if (slen == 0) + *out_obj = (MonoObject*)mono_string_empty_internal (mono_domain_get ()); + else + *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (p, slen, error); return NULL; } case MONO_TYPE_CLASS: { From ce2242ffc60db2f843ab067fb07fd8a8023061fc Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 26 Aug 2021 12:50:46 -0400 Subject: [PATCH 2/2] Add test that GetCustomAttribute returns string.Empty And not a new string object that happens to be `""` Adds a testcase for https://github.com/dotnet/runtime/pull/58023 --- .../tests/CustomAttributeTests.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/libraries/System.Reflection/tests/CustomAttributeTests.cs b/src/libraries/System.Reflection/tests/CustomAttributeTests.cs index bb9c928b542203..6b102884c0d2ca 100644 --- a/src/libraries/System.Reflection/tests/CustomAttributeTests.cs +++ b/src/libraries/System.Reflection/tests/CustomAttributeTests.cs @@ -76,5 +76,58 @@ public void AttributeWithDifferentPropertyTypes() Assert.Equal(1, attr.ObjectArray.Length); Assert.Null(attr.StringArray); } + + public class StringValuedAttribute : Attribute + { + public StringValuedAttribute (string s) + { + NamedField = s; + } + public StringValuedAttribute () {} + public string NamedProperty + { + get => NamedField; + set { NamedField = value; } + } + public string NamedField; + } + + internal class ClassWithAttrs + { + [StringValuedAttribute("")] + public void M1() {} + + [StringValuedAttribute(NamedProperty = "")] + public void M2() {} + + [StringValuedAttribute(NamedField = "")] + public void M3() {} + } + + [Fact] + public void StringAttributeValueRefEqualsStringEmpty () { + StringValuedAttribute attr; + attr = typeof (ClassWithAttrs).GetMethod("M1") + .GetCustomAttributes(typeof(StringValuedAttribute), true) + .Cast() + .Single(); + + Assert.Same(string.Empty, attr.NamedField); + + attr = typeof (ClassWithAttrs).GetMethod("M2") + .GetCustomAttributes(typeof(StringValuedAttribute), true) + .Cast() + .Single(); + + Assert.Same(string.Empty, attr.NamedField); + + + attr = typeof (ClassWithAttrs).GetMethod("M3") + .GetCustomAttributes(typeof(StringValuedAttribute), true) + .Cast() + .Single(); + + Assert.Same(string.Empty, attr.NamedField); + } } }