diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index a284f6442..5bc64a723 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -362,6 +362,7 @@ + diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs index ac1aa6c3f..ba9437dd0 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs @@ -42,7 +42,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation object constantValue; IType type; bool isVolatile; // initialized together with this.type - bool? isDecimalConstant; + // this can't be bool? as bool? is not thread-safe from torn reads + byte decimalConstantState; internal MetadataField(MetadataModule module, FieldDefinitionHandle handle) { @@ -53,9 +54,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var def = module.metadata.GetFieldDefinition(handle); this.attributes = def.Attributes; - if ((attributes & (FieldAttributes.Static | FieldAttributes.InitOnly)) != (FieldAttributes.Static | FieldAttributes.InitOnly)) { - isDecimalConstant = false; - } + if ((attributes & (FieldAttributes.Static | FieldAttributes.InitOnly)) != (FieldAttributes.Static | FieldAttributes.InitOnly)) + decimalConstantState = ThreeState.False; } public EntityHandle MetadataToken => handle; @@ -193,11 +193,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation bool IsDecimalConstant { get { - if (isDecimalConstant == null) { + if (decimalConstantState == ThreeState.Unknown) { var fieldDef = module.metadata.GetFieldDefinition(handle); - isDecimalConstant = DecimalConstantHelper.IsDecimalConstant(module, fieldDef.GetCustomAttributes()); + decimalConstantState = ThreeState.From(DecimalConstantHelper.IsDecimalConstant(module, fieldDef.GetCustomAttributes())); } - return (bool)isDecimalConstant; + return decimalConstantState == ThreeState.True; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs index 426e238d0..18871d920 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs @@ -37,8 +37,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation // lazy-loaded: string name; - bool? hasConstantValueInSignature; - bool? isDecimalConstant; + // these can't be bool? as bool? is not thread-safe from torn reads + byte constantValueInSignatureState; + byte decimalConstantState; internal MetadataParameter(MetadataModule module, IParameterizedMember owner, IType type, ParameterHandle handle) { @@ -50,7 +51,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var param = module.metadata.GetParameter(handle); this.attributes = param.Attributes; if (!IsOptional) - isDecimalConstant = false; // only optional parameters can be constants + decimalConstantState = ThreeState.False; // only optional parameters can be constants } public EntityHandle MetadataToken => handle; @@ -125,25 +126,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public bool HasConstantValueInSignature { get { - if (hasConstantValueInSignature == null) { + if (constantValueInSignatureState == ThreeState.Unknown) { if (IsDecimalConstant) { - hasConstantValueInSignature = DecimalConstantHelper.AllowsDecimalConstants(module); + constantValueInSignatureState = ThreeState.From(DecimalConstantHelper.AllowsDecimalConstants(module)); } else { - hasConstantValueInSignature = !module.metadata.GetParameter(handle).GetDefaultValue().IsNil; + constantValueInSignatureState = ThreeState.From(!module.metadata.GetParameter(handle).GetDefaultValue().IsNil); } } - return (bool)hasConstantValueInSignature; + return constantValueInSignatureState == ThreeState.True; } } bool IsDecimalConstant { get { - if (isDecimalConstant == null) { + if (decimalConstantState == ThreeState.Unknown) { var parameterDef = module.metadata.GetParameter(handle); - isDecimalConstant = DecimalConstantHelper.IsDecimalConstant(module, parameterDef.GetCustomAttributes()); + decimalConstantState = ThreeState.From(DecimalConstantHelper.IsDecimalConstant(module, parameterDef.GetCustomAttributes())); } - return (bool)isDecimalConstant; + return decimalConstantState == ThreeState.True; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/ThreeState.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/ThreeState.cs new file mode 100644 index 000000000..f558911e0 --- /dev/null +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/ThreeState.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2018 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +namespace ICSharpCode.Decompiler.TypeSystem.Implementation +{ + /// + /// Constants used instead of + /// in multithreaded code, as bool? might produce torn reads. + /// + static class ThreeState + { + public const byte Unknown = 0; + public const byte False = 1; + public const byte True = 2; + + public static byte From(bool value) => value ? True : False; + } +}