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;
+ }
+}