From c5fa794e98bd520659fdc8786511ab908ba6f1ac Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Sun, 5 Nov 2017 09:34:52 -0800 Subject: [PATCH] [bcl] Updates referencesource to 4.7.1 --- .../ReferenceSources/LocalAppContextSwitches.cs | 1 + .../SR.Designer.cs | 11 + .../Core/Presentation/CaseKeyBox.xaml.cs | 54 +- .../Core/Presentation/ParallelSeparator.xaml.cs | 5 + .../Core/Presentation/TryCatchDesigner.xaml.cs | 51 + .../Presentation/MessageQueryEditor.xaml.cs | 17 + .../Configuration/BaseConfigurationRecord.cs | 170 +- .../Configuration/Internal/DelegatingConfigHost.cs | 29 +- .../Configuration/Internal/InternalConfigHost.cs | 18 +- .../Configuration/Internal/InternalConfigRoot.cs | 12 +- .../Configuration/MgmtConfigurationRecord.cs | 14 +- .../Configuration/RuntimeConfigurationRecord.cs | 26 +- .../System/Configuration/SectionInformation.cs | 30 +- .../System/Configuration/SectionInput.cs | 20 +- .../System/Configuration/SectionXmlInfo.cs | 9 +- .../Microsoft/Scripting/Ast/LambdaExpression.cs | 15 + .../System.Core/System/IO/Pipes/Pipe.cs | 7 + .../System.Core/System/Linq/Enumerable.cs | 116 +- .../System/Security/Cryptography/BCryptNative.cs | 282 ++ .../System/Security/Cryptography/CapiNative.cs | 3 +- .../System/Security/Cryptography/RsaCng.cs | 12 +- .../ReaderWriterLockSlim/ReaderWriterLockSlim.cs | 74 +- .../Data/Common/QueryCache/QueryCacheManager.cs | 9 +- .../System.Data.Entity/Util/AppSettings.cs | 16 + .../System/Data/SqlClient/SqlConnection.cs | 22 +- .../System/Data/SqlClient/SqlDependencyListener.cs | 4 + .../System.Data/System/Data/SqlClient/TdsParser.cs | 10 +- .../System/Caching/MemoryCacheEntry.cs | 11 +- .../System/Caching/MemoryCacheKey.cs | 1 - .../System/Caching/MemoryCacheStore.cs | 38 +- .../Serialization/DataContractSerializer.cs | 5 + .../System/Runtime/ExceptionTrace.cs | 6 +- .../ServiceModel/Description/WebHttpBehavior.cs | 4 + .../AppContextDefaultValues.Default.cs | 9 + .../Channels/AddressHeaderCollection.cs | 4 +- .../System/ServiceModel/Channels/Addressing.cs | 2 +- .../ServiceModel/Channels/HttpChannelFactory.cs | 2 +- .../System/ServiceModel/Channels/Msmq.cs | 2 +- .../Channels/NamedPipeTransportBindingElement.cs | 18 +- .../System/ServiceModel/Channels/PipeConnection.cs | 16 +- .../Channels/SslStreamSecurityBindingElement.cs | 2 +- .../ServiceModel/Channels/TransportDefaults.cs | 25 +- .../ServiceModel/Channels/UnsafeNativeMethods.cs | 8 +- .../Configuration/MsmqTransportSecurityElement.cs | 4 +- .../Configuration/SslStreamSecurityElement.cs | 2 +- .../Configuration/TcpTransportSecurityElement.cs | 2 +- .../System/ServiceModel/LocalAppContextSwitches.cs | 50 +- .../System/ServiceModel/MsmqTransportSecurity.cs | 2 +- ...owsUserNameCachingSecurityTokenAuthenticator.cs | 22 +- .../System/ServiceModel/TcpTransportSecurity.cs | 2 +- .../EntityDataSourceConfigureObjectContextPanel.cs | 28 +- ...taSourceConfigureObjectContextPanel.designer.cs | 27 +- .../referencesource/System.Web/Cache/cache.cs | 3 +- .../Configuration/FormsAuthPasswordFormat.cs | 5 +- .../Configuration/HttpCapabilitiesBase.cs | 3 +- .../System.Web/Hosting/ApplicationManager.cs | 3 + .../referencesource/System.Web/HttpApplication.cs | 120 +- .../referencesource/System.Web/HttpContext.cs | 4 + mcs/class/referencesource/System.Web/HttpCookie.cs | 77 + .../referencesource/System.Web/HttpResponse.cs | 8 +- .../Security/Cryptography/CryptoAlgorithms.cs | 8 + .../System.Web/Security/FormsAuthentication.cs | 15 + .../System.Web/Security/Membership.cs | 29 +- .../referencesource/System.Web/System.Web.txt | 2 + .../referencesource/System.Web/Util/AppSettings.cs | 13 + .../System/Xml/Core/LocalAppContextSwitches.cs | 11 + .../System.Xml/System/Xml/Core/XmlConfiguration.cs | 41 + .../System/Xml/Serialization/CodeGenerator.cs | 19 +- .../Xml/Serialization/PrimitiveXmlSerializers.cs | 49 + .../System.Xml/System/Xml/Serialization/Types.cs | 6 + .../Xml/Serialization/XmlSerializationReader.cs | 70 +- .../Serialization/XmlSerializationReaderILGen.cs | 99 +- .../Xml/Serialization/XmlSerializationWriter.cs | 35 +- .../System/Xml/Serialization/XmlSerializer.cs | 22 +- .../System.Xml/System/Xml/XmlComplianceUtil.cs | 2 +- .../mscorlib/microsoft/win32/win32native.cs | 33 +- mcs/class/referencesource/mscorlib/mscorlib.txt | 9 + .../AppContextDefaultValues.DesktopOverrides.cs | 2 +- .../diagnostics/eventing/eventproviderbase.cs | 4375 -------------------- .../mscorlib/system/diagnostics/stackframe.cs | 35 +- .../mscorlib/system/diagnostics/stacktrace.cs | 221 +- .../mscorlib/system/globalization/cultureinfo.cs | 51 +- .../system/globalization/taiwancalendar.cs | 1 - .../windowsruntime/ipropertyvaluefactory.cs | 60 - .../mscorlib/system/stringcomparer.cs | 30 +- .../system/threading/Tasks/ParallelRangeManager.cs | 39 +- .../mscorlib/system/threading/Tasks/TaskFactory.cs | 18 +- mcs/class/referencesource/mscorlib/system/tuple.cs | 316 +- 88 files changed, 2296 insertions(+), 4867 deletions(-) delete mode 100644 mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventproviderbase.cs delete mode 100644 mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/ipropertyvaluefactory.cs diff --git a/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs b/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs index bc03e96bbd8..ce9e157775c 100644 --- a/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs +++ b/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs @@ -4,5 +4,6 @@ namespace System public static readonly bool IgnoreEmptyKeySequences = false; public static readonly bool DontThrowOnInvalidSurrogatePairs = false; public static readonly bool IgnoreKindInUtcTimeSerialization = false; + public static readonly bool EnableTimeSpanSerialization = false; } } \ No newline at end of file diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/SR.Designer.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/SR.Designer.cs index a1d8f4cfbb6..8447d73c6ab 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/SR.Designer.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/SR.Designer.cs @@ -846,5 +846,16 @@ namespace System.Activities.Core.Presentation { return ResourceManager.GetString("WrongNumberOfArgumentsForActivityDelegate", resourceCulture); } } + + /// + /// Looks up a localized string for the automation name of ParallelSeparator + /// + internal static string ParallelSeparatorAutomationName + { + get + { + return ResourceManager.GetString("ParallelSeparatorAutomationName", resourceCulture); + } + } } } diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/CaseKeyBox.xaml.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/CaseKeyBox.xaml.cs index 50fc58a6fa0..3b84c9285bc 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/CaseKeyBox.xaml.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/CaseKeyBox.xaml.cs @@ -7,6 +7,7 @@ namespace System.Activities.Core.Presentation using System; using System.Activities.Presentation; using System.Windows; + using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; @@ -25,7 +26,13 @@ namespace System.Activities.Core.Presentation public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.Register("ValueType", typeof(Type), typeof(CaseKeyBox), new PropertyMetadata(OnValueTypeChanged)); - + + public static readonly DependencyProperty EditorAutomationNameProperty = + DependencyProperty.Register("EditorAutomationName", typeof(string), typeof(CaseKeyBox)); + + public static readonly DependencyProperty ComboBoxAutomationNameProperty = + DependencyProperty.Register("ComboBoxAutomationName", typeof(string), typeof(CaseKeyBox)); + public static RoutedEvent ValueCommittedEvent = EventManager.RegisterRoutedEvent("ValueCommitted", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CaseKeyBox)); @@ -174,6 +181,18 @@ namespace System.Activities.Core.Presentation set { SetValue(ValueTypeProperty, value); } } + public string ComboBoxAutomationName + { + get { return (string)GetValue(ComboBoxAutomationNameProperty); } + set { SetValue(ComboBoxAutomationNameProperty, value); } + } + + public string EditorAutomationName + { + get { return (string)GetValue(EditorAutomationNameProperty); } + set { SetValue(EditorAutomationNameProperty, value); } + } + public void RegainFocus() { if (this.visibleBox != null) @@ -249,10 +268,39 @@ namespace System.Activities.Core.Presentation { UIElement box = (UIElement)sender; ComboBox comboBox = box as ComboBox; - if (comboBox != null && comboBox.IsVisible) + if (comboBox != null) + { + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + if (!string.IsNullOrEmpty(ComboBoxAutomationName)) + { + comboBox.SetValue(AutomationProperties.NameProperty, ComboBoxAutomationName); + } + if (comboBox.IsEditable && comboBox.Template != null) + { + var comboBoxTextBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox; + if (comboBoxTextBox != null && !string.IsNullOrEmpty(EditorAutomationName)) + { + comboBoxTextBox.SetValue(AutomationProperties.NameProperty, EditorAutomationName); + } + } + } + + if (comboBox.IsVisible) + { + ComboBoxHelper.SynchronizeComboBoxSelection(comboBox, this.ViewModel.Text); + } + } + + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) { - ComboBoxHelper.SynchronizeComboBoxSelection(comboBox, this.ViewModel.Text); + TextBox textBox = box as TextBox; + if (textBox != null && !string.IsNullOrEmpty(EditorAutomationName)) + { + textBox.SetValue(AutomationProperties.NameProperty, EditorAutomationName); + } } + if (box.IsVisible) { box.Focus(); diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/ParallelSeparator.xaml.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/ParallelSeparator.xaml.cs index c917004a3a0..1d68208d36b 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/ParallelSeparator.xaml.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/ParallelSeparator.xaml.cs @@ -7,6 +7,7 @@ namespace System.Activities.Core.Presentation using System.Activities.Presentation; using System.Activities.Presentation.Hosting; using System.Windows; + using System.Windows.Automation; using System.Windows.Media.Animation; partial class ParallelSeparator @@ -22,6 +23,10 @@ namespace System.Activities.Core.Presentation public ParallelSeparator() { this.InitializeComponent(); + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + SetValue(AutomationProperties.NameProperty, SR.ParallelSeparatorAutomationName); + } } public Type AllowedItemType diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/TryCatchDesigner.xaml.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/TryCatchDesigner.xaml.cs index b33dff56481..f602c593a59 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/TryCatchDesigner.xaml.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/TryCatchDesigner.xaml.cs @@ -17,6 +17,8 @@ namespace System.Activities.Core.Presentation using System.IO; using System.Runtime; using System.Windows; + using System.Windows.Automation; + using System.Windows.Automation.Peers; using System.Windows.Input; using System.Windows.Threading; using System.Windows.Controls; @@ -454,6 +456,18 @@ namespace System.Activities.Core.Presentation } } + void OnTryAddActivityKeyDown(object sender, KeyEventArgs e) + { + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + if (sender == e.OriginalSource && (e.Key == Key.Space || e.Key == Key.Enter)) + { + ExpandTryView(); + e.Handled = true; + } + } + } + void OnFinallyViewKeyDown(object sender, KeyEventArgs e) { if (sender == e.OriginalSource && (e.Key == Key.Space || e.Key == Key.Enter)) @@ -463,6 +477,18 @@ namespace System.Activities.Core.Presentation } } + void OnFinallyAddActivityKeyDown(object sender, KeyEventArgs e) + { + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + if (sender == e.OriginalSource && (e.Key == Key.Space || e.Key == Key.Enter)) + { + ExpandFinallyView(); + e.Handled = true; + } + } + } + #region AddCatch Label & TypePresenter void OnAddCatchMouseDown(object sender, MouseButtonEventArgs e) @@ -602,4 +628,29 @@ namespace System.Activities.Core.Presentation return true; } } + + internal class TextBlockWrapper : TextBlock + { + protected override AutomationPeer OnCreateAutomationPeer() + { + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + return new TextBlockWrapperAutomationPeer(this); + } + return base.OnCreateAutomationPeer(); + } + } + + internal class TextBlockWrapperAutomationPeer : TextBlockAutomationPeer + { + public TextBlockWrapperAutomationPeer(TextBlockWrapper owner) + : base(owner) + { + } + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Button; + } + } } diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/System/ServiceModel/Activities/Presentation/MessageQueryEditor.xaml.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/System/ServiceModel/Activities/Presentation/MessageQueryEditor.xaml.cs index d1b51614abd..250612b8550 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/System/ServiceModel/Activities/Presentation/MessageQueryEditor.xaml.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/System/ServiceModel/Activities/Presentation/MessageQueryEditor.xaml.cs @@ -14,6 +14,7 @@ namespace System.ServiceModel.Activities.Presentation using System.ServiceModel.Dispatcher; using System.Text; using System.Windows; + using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Input; using System.Xml; @@ -100,6 +101,22 @@ namespace System.ServiceModel.Activities.Presentation base.OnKeyDown(e); } + private void OnLoaded(object sender, RoutedEventArgs e) + { + if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + this.SetValue(AutomationProperties.NameProperty, this.Resources["MessageQueryEditorAutomationName"]); + if (this.IsEditable && this.Template != null) + { + var textBox = this.Template.FindName("PART_EditableTextBox", this) as TextBox; + if (textBox != null) + { + textBox.SetValue(AutomationProperties.NameProperty, this.GetValue(AutomationProperties.NameProperty)); + } + } + } + } + //user double clicked on the expanded type, create a xpath [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Propagating exceptions might lead to VS crash.")] diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/BaseConfigurationRecord.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/BaseConfigurationRecord.cs index 4b30c4caffe..831c5ba2282 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/BaseConfigurationRecord.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/BaseConfigurationRecord.cs @@ -60,6 +60,7 @@ namespace System.Configuration { protected const string KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS = "inheritInChildApplications"; protected const string KEYWORD_CONFIGSOURCE = "configSource"; protected const string KEYWORD_XMLNS = "xmlns"; + protected const string KEYWORD_CONFIG_BUILDER = "configBuilders"; internal const string KEYWORD_PROTECTION_PROVIDER = "configProtectionProvider"; protected const string FORMAT_NEWCONFIGFILE = "\r\n"; protected const string FORMAT_CONFIGURATION = "\r\n"; @@ -115,6 +116,8 @@ namespace System.Configuration { protected const int SuggestLocationRemoval = 0x02000000; protected const int NamespacePresentCurrent = 0x04000000; + protected const int ConfigBuildersInitialized = 0x08000000; + internal const char ConfigPathSeparatorChar = '/'; internal const string ConfigPathSeparatorString = "/"; static internal readonly char[] ConfigPathSeparatorParams = new char[] {ConfigPathSeparatorChar}; @@ -132,6 +135,7 @@ namespace System.Configuration { private ConfigRecordStreamInfo _configStreamInfo; // stream info for the config record private object _configContext; // Context for config level + private ConfigurationBuildersSection _configBuilders; // section containing the general config builders private ProtectedConfigurationSection _protectedConfig; // section containing the encryption providers private PermissionSet _restrictedPermissions; // cached restricted permission set private ConfigurationSchemaErrors _initErrors; // errors encountered during the parse of the configuration file @@ -169,7 +173,7 @@ namespace System.Configuration { protected abstract object CreateSectionFactory(FactoryRecord factoryRecord); // Create the configuration object - protected abstract object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader); + protected abstract object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, SectionInput sectionInput, object parentConfig, ConfigXmlReader reader); // Use the parent result in creating the child protected abstract object UseParentResult(string configKey, object parentResult, SectionRecord sectionRecord); @@ -819,6 +823,10 @@ namespace System.Configuration { get {return _configRoot.Host;} } + internal IInternalConfigurationBuilderHost ConfigBuilderHost { + get { return _configRoot.ConfigBuilderHost; } + } + internal BaseConfigurationRecord Parent { get {return _parent;} } @@ -1269,7 +1277,7 @@ namespace System.Configuration { sectionRecordForDefault = new SectionRecord(configKey); } - object tmpResult = CallCreateSection(true, factoryRecord, sectionRecordForDefault, null, null, null, -1); + object tmpResult = CallCreateSection(true, factoryRecord, sectionRecordForDefault, null, null, null); object tmpResultRuntimeObject; if (getRuntimeObject) { tmpResultRuntimeObject = GetRuntimeObject(tmpResult); @@ -1635,9 +1643,7 @@ namespace System.Configuration { result = UseParentResult(factoryRecord.ConfigKey, parentResult, sectionRecord); } else { - result = CallCreateSection( - isTrusted, factoryRecord, sectionRecord, parentResult, - reader, input.SectionXmlInfo.Filename, input.SectionXmlInfo.LineNumber); + result = CallCreateSection(isTrusted, factoryRecord, sectionRecord, input, parentResult, reader); } } catch (Exception e) { @@ -1847,6 +1853,12 @@ namespace System.Configuration { sectionXmlInfo.ProtectionProviderName = ValidateProtectionProviderAttribute(protectionProviderAttribute, xmlUtil); } + // Check for configBuilder + string configBuilderAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_CONFIG_BUILDER); + if (configBuilderAttribute != null) { + sectionXmlInfo.ConfigBuilderName = ValidateConfigBuilderAttribute(configBuilderAttribute, xmlUtil); + } + int lineOffset = xmlUtil.Reader.LineNumber; string rawXml = xmlUtil.CopySection(); @@ -1896,6 +1908,7 @@ namespace System.Configuration { reader = FindSection(keys, input.SectionXmlInfo, out lineNumber); } + // Decrypt protected sections if (reader != null) { if (!input.IsProtectionProviderDetermined) { input.ProtectionProvider = GetProtectionProviderFromName(input.SectionXmlInfo.ProtectionProviderName, false); @@ -1905,6 +1918,29 @@ namespace System.Configuration { reader = DecryptConfigSection(reader, input.ProtectionProvider); } } + + // Allow configBuilder a chance to modify + if (reader != null) { + if (!input.IsConfigBuilderDetermined && !String.IsNullOrWhiteSpace(input.SectionXmlInfo.ConfigBuilderName)) { + input.ConfigBuilder = GetConfigBuilderFromName(input.SectionXmlInfo.ConfigBuilderName); + } + + if (input.IsConfigBuilderDetermined) { + // Decrypt removes the invalid "configProtectionProvider" attribute simply by returning an xml reader for the + // decrypted inner xml... which persumably does not have the attribute. ConfigBuilders OTOH, will presumably + // return an xml reader based on this whole section as is. And the "configBuilders" attribute will be an + // "unrecognized attribute" further down the road. So let's remove it here. + XmlDocument doc = new XmlDocument(); + doc.PreserveWhitespace = true; + doc.LoadXml(reader.RawXml); + doc.DocumentElement.RemoveAttribute(KEYWORD_CONFIG_BUILDER); + reader = new ConfigXmlReader(doc.DocumentElement.OuterXml, filename, lineNumber); + } + + if (input.ConfigBuilder != null) { + reader = ProcessRawXml(reader, input.ConfigBuilder); + } + } } // @@ -1960,14 +1996,47 @@ namespace System.Configuration { } } - protected object CallCreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader, string filename, int line) { + internal ConfigurationBuilder GetConfigBuilderFromName(string builderName) { + if (String.IsNullOrEmpty(builderName) || ConfigBuilders == null) { + throw new ConfigurationErrorsException(SR.GetString(SR.Config_builder_not_found, builderName)); + } + + return ConfigBuilders.GetBuilderFromName(builderName); + } + + private ConfigurationBuildersSection ConfigBuilders { + get { + if (!_flags[ConfigBuildersInitialized]) { + InitConfigBuildersSection(); + } + + return _configBuilders; + } + } + + internal void InitConfigBuildersSection() { + if (!_flags[ConfigBuildersInitialized]) { + _configBuilders = GetSection(BaseConfigurationRecord.RESERVED_SECTION_CONFIGURATION_BUILDERS, false, false) as ConfigurationBuildersSection; + + _flags[ConfigBuildersInitialized] = true; + } + } + + protected object CallCreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { object config; + string filename = null; + int line = -1; + + if (sectionInput != null && sectionInput.SectionXmlInfo != null) { + filename = sectionInput.SectionXmlInfo.Filename; + line = sectionInput.SectionXmlInfo.LineNumber; + } // Call into config section while impersonating process or UNC identity // so that the section could read files from disk if needed try { using (Impersonate()) { - config = CreateSection(inputIsTrusted, factoryRecord, sectionRecord, parentConfig, reader); + config = CreateSection(inputIsTrusted, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); if (config == null && parentConfig != null) { throw new ConfigurationErrorsException(SR.GetString(SR.Config_object_is_null), filename, line); } @@ -2184,7 +2253,7 @@ namespace System.Configuration { switch (xmlUtil.Reader.Name) { case KEYWORD_SECTIONGROUP_NAME: tagName = xmlUtil.Reader.Value; - VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false); + VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false, false); break; case KEYWORD_SECTIONGROUP_TYPE: @@ -2275,7 +2344,7 @@ namespace System.Configuration { switch (xmlUtil.Reader.Name) { case KEYWORD_SECTION_NAME: tagName = xmlUtil.Reader.Value; - VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false); + VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false, true); break; case KEYWORD_SECTION_TYPE: @@ -2362,6 +2431,14 @@ namespace System.Configuration { xmlUtil.AddErrorRequiredAttribute(KEYWORD_SECTION_TYPE, ExceptionAction.Local); } + // Disallow names starting with "config" unless it is the special configBuilders section. + if (StringUtil.StartsWith(tagName, "config")) { + Type sectionType = Type.GetType(typeName); + if (!StringUtil.Equals(tagName, RESERVED_SECTION_CONFIGURATION_BUILDERS) || sectionType != ConfigurationBuildersSectionType) { + throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_cannot_begin_with_config), xmlUtil); + } + } + string configKey = CombineConfigKey(parentConfigKey, tagName); FactoryRecord factoryRecord = (FactoryRecord) factoryList[configKey]; @@ -2443,7 +2520,7 @@ namespace System.Configuration { if (xmlUtil.VerifyRequiredAttribute( name, KEYWORD_SECTION_NAME, ExceptionAction.NonSpecific)) { - VerifySectionName(name, xmlUtil, ExceptionAction.NonSpecific, false); + VerifySectionName(name, xmlUtil, ExceptionAction.NonSpecific, false, true); } } break; @@ -2864,7 +2941,8 @@ namespace System.Configuration { string configSource = null; string configSourceStreamName = null; object configSourceStreamVersion = null; - string protectionProviderName = null; + string configBuilderName = null; + string protectionProviderName = null; OverrideMode sectionLockMode = OverrideMode.Inherit; OverrideMode sectionChildLockMode = OverrideMode.Inherit; bool positionedAtNextElement = false; @@ -2946,6 +3024,16 @@ namespace System.Configuration { } } + string configBuilderAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_CONFIG_BUILDER); + if (configBuilderAttribute != null) { + try { + configBuilderName = ValidateConfigBuilderAttribute(configBuilderAttribute, xmlUtil); + } + catch (ConfigurationException ce) { + xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); + } + } + // The 2nd part of the configSource check requires advancing the reader. // Please note that this part should be done only AFTER all other attributes // checking are done. @@ -3047,7 +3135,7 @@ namespace System.Configuration { configKey, _configPath, targetConfigPath, locationSubPath, fileName, lineNumber, ConfigStreamInfo.StreamVersion, rawXml, configSource, configSourceStreamName, configSourceStreamVersion, - protectionProviderName, overrideMode, skipInChildApps); + configBuilderName, protectionProviderName, overrideMode, skipInChildApps); if (locationSubPath == null) { // @@ -3379,9 +3467,9 @@ namespace System.Configuration { return Host.IsDefinitionAllowed(_configPath, allowDefinition, allowExeDefinition); } - static protected void VerifySectionName(string name, XmlUtil xmlUtil, ExceptionAction action, bool allowImplicit) { + static protected void VerifySectionName(string name, XmlUtil xmlUtil, ExceptionAction action, bool allowImplicit, bool allowConfigNames = false) { try { - VerifySectionName(name, (IConfigErrorInfo) xmlUtil, allowImplicit); + VerifySectionName(name, (IConfigErrorInfo) xmlUtil, allowImplicit, allowConfigNames); } catch (ConfigurationErrorsException ce) { xmlUtil.SchemaErrors.AddError(ce, action); @@ -3390,7 +3478,7 @@ namespace System.Configuration { // Check if the section name contains reserved words from the config system, // and is a valid name for an XML Element. - static protected void VerifySectionName(string name, IConfigErrorInfo errorInfo, bool allowImplicit) { + static protected void VerifySectionName(string name, IConfigErrorInfo errorInfo, bool allowImplicit, bool allowConfigNames = false) { if (String.IsNullOrEmpty(name)) { throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_invalid), errorInfo); } @@ -3417,7 +3505,7 @@ namespace System.Configuration { } } - if (StringUtil.StartsWith(name, "config")) { + if (!allowConfigNames && StringUtil.StartsWith(name, "config")) { throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_cannot_begin_with_config), errorInfo); } @@ -3820,7 +3908,7 @@ namespace System.Configuration { SectionXmlInfo sectionXmlInfo = new SectionXmlInfo( configKey, _configPath, _configPath, null, ConfigStreamInfo.StreamName, 0, null, null, - null, null, null, + null, null, null, null, null, OverrideModeSetting.LocationDefault, false); SectionInput fileInput = new SectionInput(sectionXmlInfo, null); @@ -4001,6 +4089,30 @@ namespace System.Configuration { return Host.DecryptSection(encryptedXml, protectionProvider, protectedConfig); } + protected virtual XmlNode CallHostProcessRawXml(XmlNode rawXml, ConfigurationBuilder configBuilder) { + if (ConfigBuilderHost != null) { + return ConfigBuilderHost.ProcessRawXml(rawXml, configBuilder); + } + + return rawXml; + } + + protected virtual ConfigurationSection CallHostProcessConfigurationSection(ConfigurationSection configSection, ConfigurationBuilder configBuilder) { + if (ConfigBuilderHost != null) { + return ConfigBuilderHost.ProcessConfigurationSection(configSection, configBuilder); + } + + return configSection; + } + + static internal string ValidateConfigBuilderAttribute(string configBuilder, IConfigErrorInfo errorInfo) { + if (String.IsNullOrEmpty(configBuilder)) { + throw new ConfigurationErrorsException(SR.GetString(SR.Config_builder_invalid_format), errorInfo); + } + + return configBuilder; + } + static internal string ValidateProtectionProviderAttribute(string protectionProvider, IConfigErrorInfo errorInfo) { if (String.IsNullOrEmpty(protectionProvider)) { throw new ConfigurationErrorsException(SR.GetString(SR.Protection_provider_invalid_format), errorInfo); @@ -4078,6 +4190,26 @@ namespace System.Configuration { return new ConfigXmlReader(clearTextXml, filename, sectionLineNumber, true); } + private ConfigXmlReader ProcessRawXml(ConfigXmlReader reader, ConfigurationBuilder configBuilder) { + IConfigErrorInfo err = (IConfigErrorInfo)reader; + XmlNode processedXml = null; + + string filename = err.Filename; + int lineNumber = err.LineNumber; + + try { + XmlDocument doc = new XmlDocument(); + doc.PreserveWhitespace = true; + doc.LoadXml(reader.RawXml); + processedXml = CallHostProcessRawXml(doc.DocumentElement, configBuilder); + } + catch (Exception e) { + throw new ConfigurationErrorsException(SR.GetString(SR.ConfigBuilder_processXml_error, configBuilder.Name, e.Message), e, filename, lineNumber); + } + + return new ConfigXmlReader(processedXml.OuterXml, filename, lineNumber, true); + } + // ConfigContext // // Retrieve the context for the config @@ -4122,6 +4254,9 @@ namespace System.Configuration { // Note: Some of the per-attribute encryption stuff is moved to the end of the file to minimize // FI merging conflicts // + const string ConfigurationBuildersSectionTypeName = "System.Configuration.ConfigurationBuildersSection, " + AssemblyRef.SystemConfiguration; + internal const string RESERVED_SECTION_CONFIGURATION_BUILDERS = "configBuilders"; + Type ConfigurationBuildersSectionType = Type.GetType(ConfigurationBuildersSectionTypeName); const string ProtectedConfigurationSectionTypeName = "System.Configuration.ProtectedConfigurationSection, " + AssemblyRef.SystemConfiguration; internal const string RESERVED_SECTION_PROTECTED_CONFIGURATION = "configProtectedData"; internal const string Microsoft_CONFIGURATION_SECTION = ConfigurationStringConstants.WinformsApplicationConfigurationSectionName; @@ -4129,6 +4264,7 @@ namespace System.Configuration { internal static bool IsImplicitSection(string configKey) { if (string.Equals(configKey, RESERVED_SECTION_PROTECTED_CONFIGURATION, StringComparison.Ordinal) || + //string.Equals(configKey, RESERVED_SECTION_CONFIGURATION_BUILDERS, StringComparison.Ordinal) || string.Equals(configKey, Microsoft_CONFIGURATION_SECTION, StringComparison.Ordinal)) { return true; } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/DelegatingConfigHost.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/DelegatingConfigHost.cs index 8282fee66f5..4d2390a20e6 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/DelegatingConfigHost.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/DelegatingConfigHost.cs @@ -12,6 +12,7 @@ namespace System.Configuration.Internal { using System.Threading; using System.Security; using System.CodeDom.Compiler; + using System.Xml; // // A public implementation of IInternalConfigHost that simply @@ -30,15 +31,23 @@ namespace System.Configuration.Internal { // * It allows straightforward chaining of host functionality, // see UpdateConfigHost as an example. // - public class DelegatingConfigHost : IInternalConfigHost { + public class DelegatingConfigHost : IInternalConfigHost, IInternalConfigurationBuilderHost { IInternalConfigHost _host; + IInternalConfigurationBuilderHost _configBuilderHost; protected DelegatingConfigHost() {} // The host that is delegated to. protected IInternalConfigHost Host { get {return _host;} - set {_host = value;} + set { + _host = value; + _configBuilderHost = _host as IInternalConfigurationBuilderHost; + } + } + + protected IInternalConfigurationBuilderHost ConfigBuilderHost { + get { return _configBuilderHost; } } public virtual void Init(IInternalConfigRoot configRoot, params object[] hostInitParams) { @@ -226,6 +235,22 @@ namespace System.Configuration.Internal { } } + public virtual XmlNode ProcessRawXml(XmlNode rawXml, ConfigurationBuilder builder) { + if (ConfigBuilderHost != null) { + return ConfigBuilderHost.ProcessRawXml(rawXml, builder); + } + + return rawXml; + } + + public virtual ConfigurationSection ProcessConfigurationSection(ConfigurationSection configSection, ConfigurationBuilder builder) { + if (ConfigBuilderHost != null) { + return ConfigBuilderHost.ProcessConfigurationSection(configSection, builder); + } + + return configSection; + } + } } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigHost.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigHost.cs index 128702ad542..27af61e3d97 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigHost.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigHost.cs @@ -18,11 +18,12 @@ namespace System.Configuration.Internal { using System.Security.Permissions; using System.Security.Policy; using System.Threading; + using System.Xml; // // An IInternalConfigHost with common implementations of some file functions. // - internal sealed class InternalConfigHost : IInternalConfigHost { + internal sealed class InternalConfigHost : IInternalConfigHost, IInternalConfigurationBuilderHost { private IInternalConfigRoot _configRoot; internal InternalConfigHost() { @@ -446,6 +447,21 @@ namespace System.Configuration.Internal { } } + XmlNode IInternalConfigurationBuilderHost.ProcessRawXml(XmlNode rawXml, ConfigurationBuilder builder) { + if (builder != null) { + return builder.ProcessRawXml(rawXml); + } + + return rawXml; + } + + ConfigurationSection IInternalConfigurationBuilderHost.ProcessConfigurationSection(ConfigurationSection configSection, ConfigurationBuilder builder) { + if (builder != null) { + return builder.ProcessConfigurationSection(configSection); + } + + return configSection; + } } } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigRoot.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigRoot.cs index f7b2941eaeb..265e145cad6 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigRoot.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/Internal/InternalConfigRoot.cs @@ -28,11 +28,12 @@ namespace System.Configuration.Internal { // taken begin with the prefix "hl", for example, "hlFindConfigRecord". // internal sealed class InternalConfigRoot : IInternalConfigRoot { - IInternalConfigHost _host; // host, need to create records - ReaderWriterLock _hierarchyLock; // lock to protect hierarchy + IInternalConfigHost _host; // host, need to create records + IInternalConfigurationBuilderHost _configBuilderHost; // _configBuilderHost, need to create records + ReaderWriterLock _hierarchyLock; // lock to protect hierarchy BaseConfigurationRecord _rootConfigRecord; // root config record, one level above machine.config. bool _isDesignTime; // Is the hierarchy for runtime or designtime? - private Configuration _CurrentConfiguration = null; + private Configuration _CurrentConfiguration = null; public event InternalConfigEventHandler ConfigChanged; public event InternalConfigEventHandler ConfigRemoved; @@ -45,6 +46,7 @@ namespace System.Configuration.Internal { void IInternalConfigRoot.Init(IInternalConfigHost host, bool isDesignTime) { _host = host; + _configBuilderHost = host as IInternalConfigurationBuilderHost; _isDesignTime = isDesignTime; _hierarchyLock = new ReaderWriterLock(); @@ -61,6 +63,10 @@ namespace System.Configuration.Internal { get {return _host;} } + internal IInternalConfigurationBuilderHost ConfigBuilderHost { + get { return _configBuilderHost; } + } + internal BaseConfigurationRecord RootConfigRecord { get {return _rootConfigRecord;} } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/MgmtConfigurationRecord.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/MgmtConfigurationRecord.cs index f3ec52b9de8..f694686b898 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/MgmtConfigurationRecord.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/MgmtConfigurationRecord.cs @@ -141,7 +141,7 @@ namespace System.Configuration { // // Create the ConfigurationSection. // - override protected object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader) { + override protected object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { // Create an instance of the ConfigurationSection ConstructorInfo ctor = (ConstructorInfo) factoryRecord.Factory; ConfigurationSection configSection = (ConfigurationSection) TypeUtil.InvokeCtorWithReflectionPermission(ctor); @@ -157,6 +157,10 @@ namespace System.Configuration { configSection.DeserializeSection(reader); } + if (sectionInput != null && sectionInput.ConfigBuilder != null) { + configSection = CallHostProcessConfigurationSection(configSection, sectionInput.ConfigBuilder); + } + // Clear the modified bit. configSection.ResetModified(); @@ -208,7 +212,7 @@ namespace System.Configuration { throw new ConfigurationErrorsException(SR.GetString(SR.Config_unrecognized_configuration_section, configKey)); } - object result = CallCreateSection(false, factoryRecord, sectionRecord, parentResult, null, null, -1); + object result = CallCreateSection(false, factoryRecord, sectionRecord, null, parentResult, null); return result; } @@ -1647,20 +1651,24 @@ namespace System.Configuration { private bool AreSectionAttributesModified(SectionRecord sectionRecord, ConfigurationSection configSection) { string configSource; string protectionProviderName; + string configBuilderName; if (sectionRecord.HasFileInput) { SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo; configSource = sectionXmlInfo.ConfigSource; protectionProviderName = sectionXmlInfo.ProtectionProviderName; + configBuilderName = sectionXmlInfo.ConfigBuilderName; } else { configSource = null; protectionProviderName = null; + configBuilderName = null; } return !StringUtil.EqualsNE(configSource, configSection.SectionInformation.ConfigSource) || !StringUtil.EqualsNE(protectionProviderName, configSection.SectionInformation.ProtectionProviderName) + || !StringUtil.EqualsNE(configBuilderName, configSection.SectionInformation.ConfigBuilderName) || AreLocationAttributesModified(sectionRecord, configSection); } @@ -1979,6 +1987,7 @@ namespace System.Configuration { sectionRecord.ConfigKey, definitionConfigPath, _configPath, _locationSubPath, ConfigStreamInfo.StreamName, 0, ConfigStreamInfo.StreamVersion, null, configSource, configSourceStreamName, configSourceStreamVersion, + configSection.SectionInformation.ConfigBuilderName, configSection.SectionInformation.ProtectionProviderName, configSection.SectionInformation.OverrideModeSetting, !configSection.SectionInformation.InheritInChildApplications); @@ -1997,6 +2006,7 @@ namespace System.Configuration { sectionXmlInfo.ConfigSource = configSource; sectionXmlInfo.ConfigSourceStreamName = configSourceStreamName; sectionXmlInfo.ConfigSourceStreamVersion = configSourceStreamVersion; + sectionXmlInfo.ConfigBuilderName = configSection.SectionInformation.ConfigBuilderName; sectionXmlInfo.ProtectionProviderName = configSection.SectionInformation.ProtectionProviderName; sectionXmlInfo.OverrideModeSetting = configSection.SectionInformation.OverrideModeSetting; sectionXmlInfo.SkipInChildApps = !configSection.SectionInformation.InheritInChildApplications; diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/RuntimeConfigurationRecord.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/RuntimeConfigurationRecord.cs index fcc8bf4aea7..9c3d4f5d8f5 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/RuntimeConfigurationRecord.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/RuntimeConfigurationRecord.cs @@ -53,12 +53,12 @@ namespace System.Configuration { } // parentConfig contains the config that we'd merge with. - override protected object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader) { + override protected object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { // Get the factory used to create a section. RuntimeConfigurationFactory factory = (RuntimeConfigurationFactory) factoryRecord.Factory; // Use the factory to create a section. - object config = factory.CreateSection(inputIsTrusted, this, factoryRecord, sectionRecord, parentConfig, reader); + object config = factory.CreateSection(inputIsTrusted, this, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); return config; } @@ -215,7 +215,7 @@ namespace System.Configuration { private object CreateSectionImpl( RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, - object parentConfig, ConfigXmlReader reader) { + SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { object config; @@ -233,6 +233,10 @@ namespace System.Configuration { configSection.DeserializeSection(reader); } + if (configRecord != null && sectionInput != null && sectionInput.ConfigBuilder != null) { + configSection = configRecord.CallHostProcessConfigurationSection(configSection, sectionInput.ConfigBuilder); + } + // throw if there are any cached errors ConfigurationErrorsException errors = configSection.GetErrors(); if (errors != null) { @@ -270,15 +274,15 @@ namespace System.Configuration { [PermissionSet(SecurityAction.Assert, Unrestricted=true)] private object CreateSectionWithFullTrust( RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, - object parentConfig, ConfigXmlReader reader) { + SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { - return CreateSectionImpl(configRecord, factoryRecord, sectionRecord, parentConfig, reader); + return CreateSectionImpl(configRecord, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); } [SuppressMessage("Microsoft.Security", "CA2107:ReviewDenyAndPermitOnlyUsage", Justification = "This PermitOnly is meant to protect unassuming handlers from malicious callers by undoing any asserts we have put on the stack.")] private object CreateSectionWithRestrictedPermissions( - RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, - object parentConfig, ConfigXmlReader reader) { + RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord, SectionRecord sectionRecord, + SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { // run configuration section handlers as if user code was on the stack bool revertPermitOnly = false; @@ -289,7 +293,7 @@ namespace System.Configuration { revertPermitOnly = true; } - return CreateSectionImpl(configRecord, factoryRecord, sectionRecord, parentConfig, reader); + return CreateSectionImpl(configRecord, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); } finally { if (revertPermitOnly) { @@ -299,13 +303,13 @@ namespace System.Configuration { } internal object CreateSection(bool inputIsTrusted, RuntimeConfigurationRecord configRecord, - FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader) { + FactoryRecord factoryRecord, SectionRecord sectionRecord, SectionInput sectionInput, object parentConfig, ConfigXmlReader reader) { if (inputIsTrusted) { - return CreateSectionWithFullTrust(configRecord, factoryRecord, sectionRecord, parentConfig, reader); + return CreateSectionWithFullTrust(configRecord, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); } else { - return CreateSectionWithRestrictedPermissions(configRecord, factoryRecord, sectionRecord, parentConfig, reader); + return CreateSectionWithRestrictedPermissions(configRecord, factoryRecord, sectionRecord, sectionInput, parentConfig, reader); } } } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInformation.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInformation.cs index 0f0739d6ec4..0820783bf31 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInformation.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInformation.cs @@ -39,6 +39,8 @@ namespace System.Configuration { private const int Flag_ProtectionProviderModified = 0x00080000; private const int Flag_OverrideModeDefaultModified = 0x00100000; private const int Flag_OverrideModeModified = 0x00200000; // Used only for modified tracking + private const int Flag_ConfigBuilderDetermined = 0x00400000; + private const int Flag_ConfigBuilderModified = 0x00800000; private ConfigurationSection _configurationSection; private SafeBitVector32 _flags; @@ -55,6 +57,8 @@ namespace System.Configuration { private string _configSourceStreamName; private ProtectedConfigurationProvider _protectionProvider; private string _protectionProviderName; + private ConfigurationBuilder _configBuilder; + private string _configBuilderName; private OverrideModeSetting _overrideModeDefault; // The default mode for the section in _configurationSection private OverrideModeSetting _overrideMode; // The override mode at the current config path @@ -128,8 +132,10 @@ namespace System.Configuration { if (sectionRecord.HasFileInput) { SectionInput fileInput = sectionRecord.FileInput; - _flags[ Flag_ProtectionProviderDetermined ] = fileInput.IsProtectionProviderDetermined; - _protectionProvider = fileInput.ProtectionProvider; + _flags[Flag_ConfigBuilderDetermined] = fileInput.IsConfigBuilderDetermined; + _configBuilder = fileInput.ConfigBuilder; + _flags[Flag_ProtectionProviderDetermined] = fileInput.IsProtectionProviderDetermined; + _protectionProvider = fileInput.ProtectionProvider; SectionXmlInfo sectionXmlInfo = fileInput.SectionXmlInfo; @@ -137,10 +143,13 @@ namespace System.Configuration { _configSourceStreamName = sectionXmlInfo.ConfigSourceStreamName; _overrideMode = sectionXmlInfo.OverrideModeSetting; _flags[ Flag_InheritInChildApps ] = !sectionXmlInfo.SkipInChildApps; + _configBuilderName = sectionXmlInfo.ConfigBuilderName; _protectionProviderName = sectionXmlInfo.ProtectionProviderName; } else { - _flags[ Flag_ProtectionProviderDetermined ] = false; + _flags[Flag_ConfigBuilderDetermined] = false; + _configBuilder = null; + _flags[Flag_ProtectionProviderDetermined] = false; _protectionProvider = null; } @@ -599,6 +608,21 @@ namespace System.Configuration { get {return (ProtectionProvider != null);} } + internal string ConfigBuilderName { + get { return _configBuilderName; } + } + + public ConfigurationBuilder ConfigurationBuilder { + get { + if (!_flags[Flag_ConfigBuilderDetermined] && _configRecord != null) { + _configBuilder = _configRecord.GetConfigBuilderFromName(_configBuilderName); + _flags[Flag_ConfigBuilderDetermined] = true; + } + + return _configBuilder; + } + } + public ProtectedConfigurationProvider ProtectionProvider { get { if (!_flags[ Flag_ProtectionProviderDetermined] && _configRecord != null) { diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInput.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInput.cs index 7581a7990f4..6733c805b17 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInput.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionInput.cs @@ -15,8 +15,14 @@ namespace System.Configuration { private static object s_unevaluated = new object(); // input from the XML file - private SectionXmlInfo _sectionXmlInfo; + private SectionXmlInfo _sectionXmlInfo; + // Provider to enhance config sources + private ConfigurationBuilder _configBuilder; + + // Has the config provider been determined for this input? + private bool _isConfigBuilderDetermined; + // Provider to use for encryption private ProtectedConfigurationProvider _protectionProvider; @@ -79,6 +85,18 @@ namespace System.Configuration { _resultRuntimeObject = s_unevaluated; } + internal bool IsConfigBuilderDetermined { + get { return _isConfigBuilderDetermined; } + } + + internal ConfigurationBuilder ConfigBuilder { + get { return _configBuilder; } + set { + _configBuilder = value; + _isConfigBuilderDetermined = true; + } + } + internal bool IsProtectionProviderDetermined { get {return _isProtectionProviderDetermined;} } diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionXmlInfo.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionXmlInfo.cs index 415e1f0744a..e481d0b70f1 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/SectionXmlInfo.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/SectionXmlInfo.cs @@ -28,6 +28,7 @@ namespace System.Configuration { private object _configSourceStreamVersion; // version of the configSource filestream private bool _skipInChildApps; // skip inheritence by child apps? private string _rawXml; // raw xml input of the section + private string _configBuilderName; // name of the configuration provider private string _protectionProviderName; // name of the protection provider private OverrideModeSetting _overrideMode; // override mode for child config paths @@ -36,7 +37,7 @@ namespace System.Configuration { string configKey, string definitionConfigPath, string targetConfigPath, string subPath, string filename, int lineNumber, object streamVersion, string rawXml, string configSource, string configSourceStreamName, object configSourceStreamVersion, - string protectionProviderName, OverrideModeSetting overrideMode, bool skipInChildApps) { + string configBuilderName, string protectionProviderName, OverrideModeSetting overrideMode, bool skipInChildApps) { _configKey = configKey; _definitionConfigPath = definitionConfigPath; @@ -49,6 +50,7 @@ namespace System.Configuration { _configSource = configSource; _configSourceStreamName = configSourceStreamName; _configSourceStreamVersion = configSourceStreamVersion; + _configBuilderName = configBuilderName; _protectionProviderName = protectionProviderName; _overrideMode = overrideMode; _skipInChildApps = skipInChildApps; @@ -111,6 +113,11 @@ namespace System.Configuration { set {_rawXml = value;} } + internal string ConfigBuilderName { + get { return _configBuilderName; } + set { _configBuilderName = value; } + } + internal string ProtectionProviderName { get {return _protectionProviderName;} set {_protectionProviderName = value;} diff --git a/mcs/class/referencesource/System.Core/Microsoft/Scripting/Ast/LambdaExpression.cs b/mcs/class/referencesource/System.Core/Microsoft/Scripting/Ast/LambdaExpression.cs index 1318e3550a6..0059d58158b 100644 --- a/mcs/class/referencesource/System.Core/Microsoft/Scripting/Ast/LambdaExpression.cs +++ b/mcs/class/referencesource/System.Core/Microsoft/Scripting/Ast/LambdaExpression.cs @@ -145,6 +145,16 @@ namespace System.Linq.Expressions { } /// + /// Produces a delegate that represents the lambda expression. + /// + /// A that indicates if the expression should be compiled to an interpreted form, if available. + /// A delegate containing the compiled version of the lambda. + public Delegate Compile(bool preferInterpretation) + { + return Compile(); + } + + /// /// Compiles the lambda into a method definition. /// /// A which will be used to hold the lambda's IL. @@ -210,6 +220,11 @@ namespace System.Linq.Expressions { return Compile(); } + public new TDelegate Compile(bool preferInterpretation) + { + return Compile(); + } + /// /// Creates a new expression that is like this one, but using the /// supplied children. If all of the children are the same, it will diff --git a/mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs b/mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs index 7880ffd20f6..ffe4464c131 100644 --- a/mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs +++ b/mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs @@ -1182,6 +1182,7 @@ namespace System.IO.Pipes { // our WaitNamedPipe and CreateFile calls. int startTime = Environment.TickCount; int elapsed = 0; + var sw = new SpinWait(); do { // Wait for pipe to become free (this will block unless the pipe does not exist). if (!UnsafeNativeMethods.WaitNamedPipe(m_normalizedPipePath, timeout - elapsed)) { @@ -1189,6 +1190,7 @@ namespace System.IO.Pipes { // Server is not yet created so let's keep looping. if (errorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND) { + sw.SpinOnce(); continue; } @@ -1215,6 +1217,7 @@ namespace System.IO.Pipes { // Handle the possible race condition of someone else connecting to the server // between our calls to WaitNamedPipe & CreateFile. if (errorCode == UnsafeNativeMethods.ERROR_PIPE_BUSY) { + sw.SpinOnce(); continue; } @@ -1284,6 +1287,7 @@ namespace System.IO.Pipes { // straight away in such cases), and 2) when another client connects to our server in between // our WaitNamedPipe and CreateFile calls. int elapsed = 0; + var sw = new SpinWait(); do { // We want any other exception and and success to have priority over cancellation. cancellationToken.ThrowIfCancellationRequested(); @@ -1303,6 +1307,7 @@ namespace System.IO.Pipes { // Server is not yet created so let's keep looping. if (errorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND) { + sw.SpinOnce(); continue; } @@ -1311,6 +1316,7 @@ namespace System.IO.Pipes { if (cancellationToken.CanBeCanceled) { // It may not be real timeout and only checking for cancellation // let the while condition check it and decide + sw.SpinOnce(); continue; } else { @@ -1336,6 +1342,7 @@ namespace System.IO.Pipes { // Handle the possible race condition of someone else connecting to the server // between our calls to WaitNamedPipe & CreateFile. if (errorCode == UnsafeNativeMethods.ERROR_PIPE_BUSY) { + sw.SpinOnce(); continue; } diff --git a/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs b/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs index aef6a32d8ec..84a04355718 100644 --- a/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs +++ b/mcs/class/referencesource/System.Core/System/Linq/Enumerable.cs @@ -10,7 +10,7 @@ using System.Core; namespace System.Linq { - public static class Enumerable + public static partial class Enumerable { public static IEnumerable Where(this IEnumerable source, Func predicate) { if (source == null) throw Error.ArgumentNull("source"); @@ -249,6 +249,120 @@ namespace System.Linq } } + /// + /// An iterator that maps each item of an . + /// + /// The type of the source enumerable. + /// The type of the mapped items. + class SelectEnumerableIterator : Iterator, IIListProvider + { + private readonly IEnumerable _source; + private readonly Func _selector; + private IEnumerator _enumerator; + + public SelectEnumerableIterator(IEnumerable source, Func selector) + { + _source = source; + _selector = selector; + } + + public override Iterator Clone() + { + return new SelectEnumerableIterator(_source, _selector); + } + + public override void Dispose() + { + if (_enumerator != null) + { + _enumerator.Dispose(); + _enumerator = null; + } + + base.Dispose(); + } + + public override bool MoveNext() + { + switch (state) + { + case 1: + _enumerator = _source.GetEnumerator(); + state = 2; + goto case 2; + case 2: + if (_enumerator.MoveNext()) + { + current = _selector(_enumerator.Current); + return true; + } + + Dispose(); + break; + } + + return false; + } + + public override IEnumerable Select(Func selector) + { + return new SelectEnumerableIterator(_source, CombineSelectors(_selector, selector)); + } + + public override IEnumerable Where(Func predicate) + { + return new WhereEnumerableIterator(this, predicate); + } + + public TResult[] ToArray() + { + var builder = new LargeArrayBuilder(initialize: true); + + foreach (TSource item in _source) + { + builder.Add(_selector(item)); + } + + return builder.ToArray(); + } + + public List ToList() + { + var list = new List(); + + foreach (TSource item in _source) + { + list.Add(_selector(item)); + } + + return list; + } + + public int GetCount(bool onlyIfCheap) + { + // In case someone uses Count() to force evaluation of + // the selector, run it provided `onlyIfCheap` is false. + + if (onlyIfCheap) + { + return -1; + } + + int count = 0; + + foreach (TSource item in _source) + { + _selector(item); + checked + { + count++; + } + } + + return count; + } + } + class WhereSelectEnumerableIterator : Iterator { IEnumerable source; diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs index 52532d2e2f3..7bbe4cda955 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs @@ -173,6 +173,17 @@ namespace System.Security.Cryptography { internal int cbSalt; } + [StructLayout(LayoutKind.Sequential)] + private struct BCRYPT_KEY_DATA_BLOB_HEADER + { + public uint dwMagic; + public uint dwVersion; + public uint cbKeyData; + + public const uint BCRYPT_KEY_DATA_BLOB_MAGIC = 0x4d42444b; + public const uint BCRYPT_KEY_DATA_BLOB_VERSION1 = 0x1; + } + /// /// Well known KDF names /// @@ -295,6 +306,120 @@ namespace System.Security.Cryptography { [In] int dwFlags, [In] IntPtr pvAuxInfo, [Out] out SafeBCryptKeyHandle phKey); + + [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern ErrorCode BCryptImportKey( + SafeBCryptAlgorithmHandle hAlgorithm, + IntPtr hImportKey, + string pszBlobType, + out SafeBCryptKeyHandle hKey, + IntPtr pbKeyObject, + int cbKeyObject, + byte[] pbInput, + int cbInput, + int dwFlags); + + [DllImport("bcrypt.dll", SetLastError = true)] + public static extern unsafe ErrorCode BCryptEncrypt( + SafeBCryptKeyHandle hKey, + byte* pbInput, + int cbInput, + IntPtr paddingInfo, + [In, Out] byte[] pbIV, + int cbIV, + byte* pbOutput, + int cbOutput, + out int cbResult, + int dwFlags); + + [DllImport("bcrypt.dll", SetLastError = true)] + public static extern unsafe ErrorCode BCryptDecrypt( + SafeBCryptKeyHandle hKey, + byte* pbInput, + int cbInput, + IntPtr paddingInfo, + [In, Out] byte[] pbIV, + int cbIV, + byte* pbOutput, + int cbOutput, + out int cbResult, + int dwFlags); + + [DllImport("bcrypt.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern ErrorCode BCryptSetProperty( + SafeBCryptAlgorithmHandle hObject, + string pszProperty, + string pbInput, + int cbInput, + int dwFlags); + } + + [SecuritySafeCritical] + internal static class AesBCryptModes + { + [SecurityCritical] + private static readonly SafeBCryptAlgorithmHandle s_hAlgCbc = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_CBC); + + [SecurityCritical] + private static readonly SafeBCryptAlgorithmHandle s_hAlgEcb = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_ECB); + + internal static SafeBCryptAlgorithmHandle GetSharedHandle(CipherMode cipherMode) + { + // Windows 8 added support to set the CipherMode value on a key, + // but Windows 7 requires that it be set on the algorithm before key creation. + switch (cipherMode) + { + case CipherMode.CBC: + return s_hAlgCbc; + case CipherMode.ECB: + return s_hAlgEcb; + default: + throw new NotSupportedException(); + } + } + + private static SafeBCryptAlgorithmHandle OpenAesAlgorithm(string cipherMode) + { + const string BCRYPT_AES_ALGORITHM = "AES"; + SafeBCryptAlgorithmHandle hAlg = OpenAlgorithm(BCRYPT_AES_ALGORITHM, null); + SetCipherMode(hAlg, cipherMode); + + return hAlg; + } + } + + [SecuritySafeCritical] + internal static class TripleDesBCryptModes + { + [SecurityCritical] + private static readonly SafeBCryptAlgorithmHandle s_hAlgCbc = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_CBC); + + [SecurityCritical] + private static readonly SafeBCryptAlgorithmHandle s_hAlgEcb = OpenAesAlgorithm(Interop.BCrypt.BCRYPT_CHAIN_MODE_ECB); + + internal static SafeBCryptAlgorithmHandle GetSharedHandle(CipherMode cipherMode) + { + // Windows 8 added support to set the CipherMode value on a key, + // but Windows 7 requires that it be set on the algorithm before key creation. + switch (cipherMode) + { + case CipherMode.CBC: + return s_hAlgCbc; + case CipherMode.ECB: + return s_hAlgEcb; + default: + throw new NotSupportedException(); + } + } + + private static SafeBCryptAlgorithmHandle OpenAesAlgorithm(string cipherMode) + { + const string BCRYPT_3DES_ALGORITHM = "3DES"; + SafeBCryptAlgorithmHandle hAlg = OpenAlgorithm(BCRYPT_3DES_ALGORITHM, null); + SetCipherMode(hAlg, cipherMode); + + return hAlg; + } } // @@ -493,6 +618,163 @@ namespace System.Security.Cryptography { } return keyBlob; } + + + [SecuritySafeCritical] + internal static SafeBCryptKeyHandle BCryptImportKey(SafeBCryptAlgorithmHandle hAlg, byte[] key) + { + unsafe + { + const String BCRYPT_KEY_DATA_BLOB = "KeyDataBlob"; + int keySize = key.Length; + int blobSize = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) keySize; + byte[] blob = new byte[blobSize]; + fixed (byte* pbBlob = blob) + { + BCRYPT_KEY_DATA_BLOB_HEADER* pBlob = (BCRYPT_KEY_DATA_BLOB_HEADER*)pbBlob; + pBlob->dwMagic = BCRYPT_KEY_DATA_BLOB_HEADER.BCRYPT_KEY_DATA_BLOB_MAGIC; + pBlob->dwVersion = BCRYPT_KEY_DATA_BLOB_HEADER.BCRYPT_KEY_DATA_BLOB_VERSION1; + pBlob->cbKeyData = (uint)keySize; + } + Buffer.BlockCopy(key, 0, blob, sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), keySize); + SafeBCryptKeyHandle hKey; + + ErrorCode error = UnsafeNativeMethods.BCryptImportKey( + hAlg, + IntPtr.Zero, + BCRYPT_KEY_DATA_BLOB, + out hKey, + IntPtr.Zero, + 0, + blob, + blobSize, + 0); + + if (error != ErrorCode.Success) + throw new CryptographicException((int)error); + + return hKey; + } + } + + // Note: input and output are allowed to be the same buffer. + // BCryptEncrypt will correctly do the encryption in place according to CNG documentation. + [SecuritySafeCritical] + public static int BCryptEncrypt( + SafeBCryptKeyHandle hKey, + byte[] input, + int inputOffset, + int inputCount, + byte[] iv, + byte[] output, + int outputOffset, + int outputCount) + { + Debug.Assert(input != null); + Debug.Assert(inputOffset >= 0); + Debug.Assert(inputCount >= 0); + Debug.Assert(inputCount <= input.Length - inputOffset); + Debug.Assert(output != null); + Debug.Assert(outputOffset >= 0); + Debug.Assert(outputCount >= 0); + Debug.Assert(outputCount <= output.Length - outputOffset); + + unsafe + { + fixed (byte* pbInput = input) + { + fixed (byte* pbOutput = output) + { + int cbResult; + ErrorCode error = UnsafeNativeMethods.BCryptEncrypt( + hKey, + pbInput inputOffset, + inputCount, + IntPtr.Zero, + iv, + iv == null ? 0 : iv.Length, + pbOutput outputOffset, + outputCount, + out cbResult, + 0); + + if (error != ErrorCode.Success) + throw new CryptographicException((int)error); + + return cbResult; + } + } + } + } + + // Note: input and output are allowed to be the same buffer. + // BCryptDecrypt will correctly do the decryption in place according to CNG documentation. + [SecuritySafeCritical] + public static int BCryptDecrypt( + SafeBCryptKeyHandle hKey, + byte[] input, + int inputOffset, + int inputCount, + byte[] iv, + byte[] output, + int outputOffset, + int outputCount) + { + Debug.Assert(input != null); + Debug.Assert(inputOffset >= 0); + Debug.Assert(inputCount >= 0); + Debug.Assert(inputCount <= input.Length - inputOffset); + Debug.Assert(output != null); + Debug.Assert(outputOffset >= 0); + Debug.Assert(outputCount >= 0); + Debug.Assert(outputCount <= output.Length - outputOffset); + + unsafe + { + fixed (byte* pbInput = input) + { + fixed (byte* pbOutput = output) + { + int cbResult; + ErrorCode error = UnsafeNativeMethods.BCryptDecrypt( + hKey, + pbInput inputOffset, + inputCount, + IntPtr.Zero, + iv, + iv == null ? 0 : iv.Length, + pbOutput outputOffset, + outputCount, + out cbResult, + 0); + + if (error != ErrorCode.Success) + throw new CryptographicException((int)error); + + return cbResult; + } + } + } + } + + [SecurityCritical] + public static void SetCipherMode(SafeBCryptAlgorithmHandle hAlg, string cipherMode) + { + const string BCRYPT_CHAINING_MODE = "ChainingMode"; + + ErrorCode error = UnsafeNativeMethods.BCryptSetProperty( + hAlg, + BCRYPT_CHAINING_MODE, + cipherMode, + // Explicit \0 terminator, UCS-2 + (cipherMode.Length 1) * 2, + 0); + + if (error != ErrorCode.Success) + { + throw new CryptographicException((int)error); + } + } #endif } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs index cbf1971793d..436463705a2 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs @@ -976,7 +976,8 @@ namespace System.Security.Cryptography { : base(true) { } - [DllImport("kernel32.dll")] + [DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity] + [SecurityCritical] private static extern IntPtr LocalFree(IntPtr hMem); [SecuritySafeCritical] diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs index ca99748e84c..15c809bb4de 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs @@ -87,6 +87,7 @@ namespace System.Security.Cryptography /// if is not an RSA key /// if is null. [SecuritySafeCritical] + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] public RSACng(CngKey key) { if (key == null) @@ -115,6 +116,7 @@ namespace System.Security.Cryptography public CngKey Key { [SecuritySafeCritical] + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] get { // If our key size was changed from the key we're using, we need to generate a new key @@ -133,15 +135,15 @@ namespace System.Security.Cryptography }; CngProperty keySizeProperty = new CngProperty(NCryptNative.KeyPropertyName.Length, - BitConverter.GetBytes(KeySize), - CngPropertyOptions.None); + BitConverter.GetBytes(KeySize), + CngPropertyOptions.None); creationParameters.Parameters.Add(keySizeProperty); _key = CngKey.Create(CngAlgorithm.Rsa, null, creationParameters); } return _key; } - + private set { Debug.Assert(value != null, "value != null"); @@ -181,6 +183,7 @@ namespace System.Security.Cryptography private SafeNCryptKeyHandle KeyHandle { [SecuritySafeCritical] + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] get { return Key.Handle; } } @@ -442,7 +445,7 @@ namespace System.Security.Cryptography throw new ArgumentNullException("padding"); } - SafeNCryptKeyHandle keyHandle = Key.Handle; + SafeNCryptKeyHandle keyHandle = KeyHandle; if (padding == RSAEncryptionPadding.Pkcs1) { @@ -492,6 +495,7 @@ namespace System.Security.Cryptography // [SecuritySafeCritical] + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (hash == null) diff --git a/mcs/class/referencesource/System.Core/System/threading/ReaderWriterLockSlim/ReaderWriterLockSlim.cs b/mcs/class/referencesource/System.Core/System/threading/ReaderWriterLockSlim/ReaderWriterLockSlim.cs index aeff48d0040..967fdb8154c 100644 --- a/mcs/class/referencesource/System.Core/System/threading/ReaderWriterLockSlim/ReaderWriterLockSlim.cs +++ b/mcs/class/referencesource/System.Core/System/threading/ReaderWriterLockSlim/ReaderWriterLockSlim.cs @@ -412,7 +412,7 @@ namespace System.Threading continue; // since we left the lock, start over. } - retVal = WaitOnEvent(readEvent, ref numReadWaiters, timeout); + retVal = WaitOnEvent(readEvent, ref numReadWaiters, timeout, isWriteWaiter: false); if (!retVal) { return false; @@ -586,7 +586,7 @@ namespace System.Threading Debug.Assert(numWriteUpgradeWaiters == 0, "There can be at most one thread with the upgrade lock held."); - retVal = WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, timeout); + retVal = WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, timeout, isWriteWaiter: true); //The lock is not held in case of failure. if (!retVal) @@ -601,7 +601,7 @@ namespace System.Threading continue; // since we left the lock, start over. } - retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, timeout); + retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, timeout, isWriteWaiter: true); //The lock is not held in case of failure. if (!retVal) return false; @@ -757,7 +757,7 @@ namespace System.Threading } //Only one thread with the upgrade lock held can proceed. - retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, timeout); + retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, timeout, isWriteWaiter: false); if (!retVal) return false; } @@ -956,7 +956,11 @@ namespace System.Threading /// Waits on 'waitEvent' with a timeout /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine. /// - private bool WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, TimeoutTracker timeout) + private bool WaitOnEvent( + EventWaitHandle waitEvent, + ref uint numWaiters, + TimeoutTracker timeout, + bool isWriteWaiter) { #if DEBUG Debug.Assert(MyLockHeld); @@ -991,8 +995,17 @@ namespace System.Threading if (numWriteUpgradeWaiters == 0) ClearUpgraderWaiting(); - if (!waitSuccessful) // We may also be aboutto throw for some reason. Exit myLock. - ExitMyLock(); + if (!waitSuccessful) // We may also be about to throw for some reason. Exit myLock. + { + if (isWriteWaiter) + { + // Write waiters block read waiters from acquiring the lock. Since this was the last write waiter, try + // to wake up the appropriate read waiters. + ExitAndWakeUpAppropriateReadWaiters(); + } + else + ExitMyLock(); + } } return waitSuccessful; } @@ -1016,8 +1029,6 @@ namespace System.Threading private void ExitAndWakeUpAppropriateWaitersPreferringWriters() { - bool setUpgradeEvent = false; - bool setReadEvent = false; uint readercount = GetNumReaders(); //We need this case for EU->ER->EW case, as the read count will be 2 in @@ -1046,31 +1057,36 @@ namespace System.Threading ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) writeEvent.Set(); // release one writer. } - else if (readercount >= 0) + else { - if (numReadWaiters != 0 || numUpgradeWaiters != 0) - { - if (numReadWaiters != 0) - setReadEvent = true; + ExitAndWakeUpAppropriateReadWaiters(); + } + } - if (numUpgradeWaiters != 0 && upgradeLockOwnerId == -1) - { - setUpgradeEvent = true; - } + private void ExitAndWakeUpAppropriateReadWaiters() + { +#if DEBUG + Debug.Assert(MyLockHeld); +#endif - ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) + if (numWriteWaiters != 0 || numWriteUpgradeWaiters != 0 || fNoWaiters) + { + ExitMyLock(); + return; + } - if (setReadEvent) - readEvent.Set(); // release all readers. + Debug.Assert(numReadWaiters != 0 || numUpgradeWaiters != 0); - if (setUpgradeEvent) - upgradeEvent.Set(); //release one upgrader. - } - else - ExitMyLock(); - } - else - ExitMyLock(); + bool setReadEvent = numReadWaiters != 0; + bool setUpgradeEvent = numUpgradeWaiters != 0 && upgradeLockOwnerId == -1; + + ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock) + + if (setReadEvent) + readEvent.Set(); // release all readers. + + if (setUpgradeEvent) + upgradeEvent.Set(); //release one upgrader. } private bool IsWriterAcquired() diff --git a/mcs/class/referencesource/System.Data.Entity/System/Data/Common/QueryCache/QueryCacheManager.cs b/mcs/class/referencesource/System.Data.Entity/System/Data/Common/QueryCache/QueryCacheManager.cs index 7bbc1a39204..e4b471c2976 100644 --- a/mcs/class/referencesource/System.Data.Entity/System/Data/Common/QueryCache/QueryCacheManager.cs +++ b/mcs/class/referencesource/System.Data.Entity/System/Data/Common/QueryCache/QueryCacheManager.cs @@ -17,6 +17,7 @@ namespace System.Data.Common.QueryCache using System.Diagnostics; using System.Threading; using System.Data.Common.Internal.Materialization; + using System.Data.Entity.Util; /// /// Provides Query Execution Plan Caching Service @@ -28,12 +29,6 @@ namespace System.Data.Common.QueryCache internal class QueryCacheManager : IDisposable { #region Constants/Default values for configuration parameters - - /// - /// Default Soft maximum number of entries in the cache - /// Default value: 1000 - /// - const int DefaultMaxNumberOfEntries = 1000; /// /// Default high mark for starting sweeping process @@ -85,7 +80,7 @@ namespace System.Data.Common.QueryCache /// A new instance of configured with default entry count, load factor and recycle period internal static QueryCacheManager Create() { - return new QueryCacheManager(DefaultMaxNumberOfEntries, DefaultHighMarkPercentageFactor, DefaultRecyclerPeriodInMilliseconds); + return new QueryCacheManager(AppSettings.QueryCacheSize, DefaultHighMarkPercentageFactor, DefaultRecyclerPeriodInMilliseconds); } /// diff --git a/mcs/class/referencesource/System.Data.Entity/Util/AppSettings.cs b/mcs/class/referencesource/System.Data.Entity/Util/AppSettings.cs index 2617ed2dfc2..0862520d8de 100644 --- a/mcs/class/referencesource/System.Data.Entity/Util/AppSettings.cs +++ b/mcs/class/referencesource/System.Data.Entity/Util/AppSettings.cs @@ -41,6 +41,11 @@ namespace System.Data.Entity.Util _SimplifyUserSpecifiedViews = true; } + if (settings == null || !int.TryParse(settings["EntityFramework_QueryCacheSize"], out _QueryCacheSize) || _QueryCacheSize < 1) + { + _QueryCacheSize = DefaultQueryCacheSize; + } + _settingsInitialized = true; } } @@ -67,5 +72,16 @@ namespace System.Data.Entity.Util return _SimplifyUserSpecifiedViews; } } + + private static int _QueryCacheSize; + private const int DefaultQueryCacheSize = 1000; + internal static int QueryCacheSize + { + get + { + EnsureSettingsLoaded(); + return _QueryCacheSize; + } + } } } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs index 577b5961f99..92158691a5e 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs @@ -1097,6 +1097,10 @@ namespace System.Data.SqlClient } finally { SqlStatistics.StopTimer(statistics); + //dispose windows identity once connection is closed. + if (_lastIdentity != null) { + _lastIdentity.Dispose(); + } } } finally { @@ -1495,14 +1499,16 @@ namespace System.Data.SqlClient } if (_impersonateIdentity != null) { - if (_impersonateIdentity.User == DbConnectionPoolIdentity.GetCurrentWindowsIdentity().User) { - return TryOpenInner(retry); - } - else { - using (WindowsImpersonationContext context = _impersonateIdentity.Impersonate()) { - return TryOpenInner(retry); - } - } + using (WindowsIdentity identity = DbConnectionPoolIdentity.GetCurrentWindowsIdentity()) { + if (_impersonateIdentity.User == identity.User) { + return TryOpenInner(retry); + } + else { + using (WindowsImpersonationContext context = _impersonateIdentity.Impersonate()) { + return TryOpenInner(retry); + } + } + } } else { if (this.UsesIntegratedSecurity(connectionOptions) || this.UsesActiveDirectoryIntegrated(connectionOptions)) { diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlDependencyListener.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlDependencyListener.cs index 656d0dd6db1..b4ddd26f4c3 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlDependencyListener.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlDependencyListener.cs @@ -914,6 +914,10 @@ internal class SqlDependencyProcessDispatcher : MarshalByRefObject { // MBR sinc finally { _stopped = true; _con.Dispose(); // Close and dispose connection. + //dispose windows identity + if (_windowsIdentity != null) { + _windowsIdentity.Dispose(); + } } } } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsParser.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsParser.cs index 3d3d95f3f6d..bc0bb7e3584 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsParser.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsParser.cs @@ -856,8 +856,6 @@ namespace System.Data.SqlClient { bool isYukonOrLater = false; - // - Debug.Assert(_physicalStateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); bool result = _physicalStateObj.TryReadNetworkPacket(); if (!result) { throw SQL.SynchronousCallMayNotPend(); } @@ -869,8 +867,12 @@ namespace System.Data.SqlClient { ThrowExceptionAndWarning(_physicalStateObj); } - // SEC - byte[] payload = new byte[_physicalStateObj._inBytesRead - _physicalStateObj._inBytesUsed - _physicalStateObj._inputHeaderLen]; + if (!_physicalStateObj.TryProcessHeader()) { throw SQL.SynchronousCallMayNotPend(); } + + if (_physicalStateObj._inBytesPacket > TdsEnums.MAX_PACKET_SIZE || _physicalStateObj._inBytesPacket <= 0) { + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + byte[] payload = new byte[_physicalStateObj._inBytesPacket]; Debug.Assert(_physicalStateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); result = _physicalStateObj.TryReadByteArray(payload, 0, payload.Length); diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheEntry.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheEntry.cs index de32f8fcd86..ba45af1fb83 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheEntry.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheEntry.cs @@ -6,13 +6,14 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; +using System.Threading; namespace System.Runtime.Caching { internal class MemoryCacheEntry: MemoryCacheKey { - const byte EntryStateMask = 0x1f; private Object _value; private DateTime _utcCreated; + private int _state; // expiration private DateTime _utcAbsExp; private TimeSpan _slidingExp; @@ -69,8 +70,8 @@ namespace System.Runtime.Caching { } internal EntryState State { - get { return (EntryState)(_bits & EntryStateMask); } - set { _bits = (byte)(((uint)_bits & ~(uint)EntryStateMask) | (uint)value); } + get { return (EntryState)_state; } + set { _state = (int)value; } } internal byte UsageBucket { @@ -169,6 +170,10 @@ namespace System.Runtime.Caching { } } + internal bool CompareExchangeState(EntryState value, EntryState comparand) { + return (Interlocked.CompareExchange(ref _state, (int)value, (int)comparand) == (int)comparand); + } + // Associates this entry with an update sentinel. If this entry has a sliding expiration, we need to // touch the sentinel so that it doesn't expire. internal void ConfigureUpdateSentinel(MemoryCacheStore sentinelStore, MemoryCacheEntry sentinelEntry) { diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheKey.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheKey.cs index f6b9b4e78e7..11da958ebbb 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheKey.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheKey.cs @@ -9,7 +9,6 @@ namespace System.Runtime.Caching { internal class MemoryCacheKey { private String _key; private int _hash; - protected byte _bits; internal int Hash { get { return _hash; } } internal String Key { get { return _key; } } diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStore.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStore.cs index 45128a44bc7..3e49e5b6b3a 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStore.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStore.cs @@ -38,24 +38,37 @@ namespace System.Runtime.Caching { // private members private void AddToCache(MemoryCacheEntry entry) { + // add outside of lock - if (entry != null) { - if (entry.HasExpiration()) { - _expires.Add(entry); - } + if (entry == null) { + return; + } - if (entry.HasUsage() - && (!entry.HasExpiration() || entry.UtcAbsExp - DateTime.UtcNow >= CacheUsage.MIN_LIFETIME_FOR_USAGE)) { - _usage.Add(entry); + if (entry.HasExpiration()) { + _expires.Add(entry); + } + + if (entry.HasUsage() + && (!entry.HasExpiration() || entry.UtcAbsExp - DateTime.UtcNow >= CacheUsage.MIN_LIFETIME_FOR_USAGE)) { + _usage.Add(entry); + } + + // One last sanity check to be sure we didn't fall victim to an Add ---- + if (!entry.CompareExchangeState(EntryState.AddedToCache, EntryState.AddingToCache)) { + if (entry.InExpires()) { + _expires.Remove(entry); } - entry.State = EntryState.AddedToCache; - entry.CallNotifyOnChanged(); - if (_perfCounters != null) { - _perfCounters.Increment(PerfCounterName.Entries); - _perfCounters.Increment(PerfCounterName.Turnover); + if (entry.InUsage()) { + _usage.Remove(entry); } } + + entry.CallNotifyOnChanged(); + if (_perfCounters != null) { + _perfCounters.Increment(PerfCounterName.Entries); + _perfCounters.Increment(PerfCounterName.Turnover); + } } private void InitDisposableMembers() { @@ -291,6 +304,7 @@ namespace System.Runtime.Caching { if (added) { AddToCache(entry); } + // Dev10 861163: Call Release after the new entry has been completely added so // that the CacheItemRemovedCallback can take a dependency on the newly inserted item. if (existingEntry != null) { diff --git a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContractSerializer.cs b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContractSerializer.cs index b9445f4d2eb..6a6bb5100a8 100644 --- a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContractSerializer.cs +++ b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContractSerializer.cs @@ -426,6 +426,11 @@ namespace System.Runtime.Serialization } } + internal void SetDataContractSurrogate(IDataContractSurrogate adapter) + { + dataContractSurrogate = adapter; + } + internal override void InternalWriteEndObject(XmlWriterDelegator writer) { if (!IsRootXmlAny(rootName, RootContract)) diff --git a/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/ExceptionTrace.cs b/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/ExceptionTrace.cs index 541e17eace5..c040bc4a632 100644 --- a/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/ExceptionTrace.cs +++ b/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/ExceptionTrace.cs @@ -249,19 +249,19 @@ namespace System.Runtime { case TraceEventType.Error: case TraceEventType.Warning: - if (TraceCore.ThrowingExceptionIsEnabled(this.diagnosticTrace)) + if (TraceCore.ThrowingEtwExceptionIsEnabled(this.diagnosticTrace)) { TraceCore.ThrowingEtwException(this.diagnosticTrace, this.eventSourceName, exception != null ? exception.ToString() : string.Empty, exception); } break; case TraceEventType.Critical: - if (TraceCore.UnhandledExceptionIsEnabled(this.diagnosticTrace)) + if (TraceCore.EtwUnhandledExceptionIsEnabled(this.diagnosticTrace)) { TraceCore.EtwUnhandledException(this.diagnosticTrace, exception != null ? exception.ToString() : string.Empty, exception); } break; default: - if (TraceCore.ThrowingExceptionVerboseIsEnabled(this.diagnosticTrace)) + if (TraceCore.ThrowingEtwExceptionVerboseIsEnabled(this.diagnosticTrace)) { TraceCore.ThrowingEtwExceptionVerbose(this.diagnosticTrace, this.eventSourceName, exception != null ? exception.ToString() : string.Empty, exception); } diff --git a/mcs/class/referencesource/System.ServiceModel.Web/System/ServiceModel/Description/WebHttpBehavior.cs b/mcs/class/referencesource/System.ServiceModel.Web/System/ServiceModel/Description/WebHttpBehavior.cs index 83b5943fbc2..7538ece4fa6 100644 --- a/mcs/class/referencesource/System.ServiceModel.Web/System/ServiceModel/Description/WebHttpBehavior.cs +++ b/mcs/class/referencesource/System.ServiceModel.Web/System/ServiceModel/Description/WebHttpBehavior.cs @@ -405,6 +405,10 @@ namespace System.ServiceModel.Description { attributes = od.BeginMethod.GetCustomAttributes(typeof(DescriptionAttribute), true); } + else if (od.TaskMethod != null) + { + attributes = od.TaskMethod.GetCustomAttributes(typeof(DescriptionAttribute), true); + } if (attributes != null && attributes.Length > 0) { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs index a41685a719f..43a4388b32a 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs @@ -38,6 +38,15 @@ namespace System LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DisableUsingServicePointManagerSecurityProtocolsString, true); } + if (version <= 40700) + { + // Define the switches that should be true for 4.7.0 or less, false for 4.7.1+. + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.UseSha1InPipeConnectionGetHashAlgorithmString, true); + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DisableAddressHeaderCollectionValidationString, true); + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.UseSha1InMsmqEncryptionAlgorithmString, true); + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSystemDefaultTlsVersionsString, true); + } + break; } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/AddressHeaderCollection.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/AddressHeaderCollection.cs index a249d56a9a9..81e4704f602 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/AddressHeaderCollection.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/AddressHeaderCollection.cs @@ -38,11 +38,11 @@ namespace System.ServiceModel.Channels throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderIsNull0))); } } - else + else if (!LocalAppContextSwitches.DisableAddressHeaderCollectionValidation) { foreach (AddressHeader addressHeader in addressHeaders) { - if (addressHeaders == null) + if (addressHeader == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderIsNull0))); } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Addressing.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Addressing.cs index e0f325c1f74..36a70ba9c99 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Addressing.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Addressing.cs @@ -466,7 +466,7 @@ namespace System.ServiceModel.Channels if (actor.Length == 0 && mustUnderstand == mustUnderstandValue && !relay) { - if ((object)to == (object)version.Anonymous) + if ((object)to == (object)version.AnonymousUri) { if (version == AddressingVersion.WSAddressing10) return AnonymousTo10; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelFactory.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelFactory.cs index 323b2541503..43a150ff27d 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelFactory.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelFactory.cs @@ -302,7 +302,7 @@ namespace System.ServiceModel.Channels { if (this.hashAlgorithm == null) { - this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest); + this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest); } else { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Msmq.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Msmq.cs index 8382fd5fc9f..5d13e1da620 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Msmq.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/Msmq.cs @@ -114,7 +114,7 @@ namespace System.ServiceModel.Channels if (null == errorStrings) { #pragma warning suppress 56523 // Callers (there is only one) handle an invalid handle returned from here. - errorStrings = UnsafeNativeMethods.LoadLibrary("MQUTIL.DLL"); + errorStrings = UnsafeNativeMethods.LoadLibraryEx("MQUTIL.DLL", IntPtr.Zero, UnsafeNativeMethods.LOAD_LIBRARY_AS_DATAFILE | UnsafeNativeMethods.LOAD_LIBRARY_SEARCH_SYSTEM32); } } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs index d2a23342859..82391231883 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs @@ -5,12 +5,14 @@ namespace System.ServiceModel.Channels { using System.Collections.Generic; + using Collections.ObjectModel; using System.Security.Principal; using System.ServiceModel.Activation; public class NamedPipeTransportBindingElement : ConnectionOrientedTransportBindingElement { - List allowedUsers; + List allowedUsers = new List(); + Collection allowedUsersCollection; NamedPipeConnectionPoolSettings connectionPoolSettings = new NamedPipeConnectionPoolSettings(); NamedPipeSettings settings = new NamedPipeSettings(); @@ -24,7 +26,6 @@ namespace System.ServiceModel.Channels { if (elementToBeCloned.allowedUsers != null) { - this.allowedUsers = new List(elementToBeCloned.AllowedUsers.Count); foreach (SecurityIdentifier id in elementToBeCloned.allowedUsers) { this.allowedUsers.Add(id); @@ -48,6 +49,19 @@ namespace System.ServiceModel.Channels } } + public Collection AllowedSecurityIdentifiers + { + get + { + if (this.allowedUsersCollection == null) + { + this.allowedUsersCollection = new Collection(this.allowedUsers); + } + + return this.allowedUsersCollection; + } + } + public NamedPipeConnectionPoolSettings ConnectionPoolSettings { get { return this.connectionPoolSettings; } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs index 9b1f4f0e003..16f89740523 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs @@ -2840,10 +2840,20 @@ namespace System.ServiceModel.Channels [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. It will cause compatibility issue. Not used for cryptographic purposes.")] static HashAlgorithm GetHashAlgorithm() { - if (SecurityUtilsEx.RequiresFipsCompliance) - return new SHA1CryptoServiceProvider(); + if (!LocalAppContextSwitches.UseSha1InPipeConnectionGetHashAlgorithm) + { + if (SecurityUtilsEx.RequiresFipsCompliance) + return new SHA256CryptoServiceProvider(); + else + return new SHA256Managed(); + } else - return new SHA1Managed(); + { + if (SecurityUtilsEx.RequiresFipsCompliance) + return new SHA1CryptoServiceProvider(); + else + return new SHA1Managed(); + } } public static string GetPath(Uri uri) diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/SslStreamSecurityBindingElement.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/SslStreamSecurityBindingElement.cs index 957aefd915a..a3430dd2ca7 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/SslStreamSecurityBindingElement.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/SslStreamSecurityBindingElement.cs @@ -68,7 +68,7 @@ namespace System.ServiceModel.Channels } } - [DefaultValue(TransportDefaults.SslProtocols)] + [DefaultValue(TransportDefaults.OldDefaultSslProtocols)] public SslProtocols SslProtocols { get diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs index d2c0f72a516..c10c7f57b46 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs @@ -163,7 +163,8 @@ namespace System.ServiceModel.Channels internal const int MaxPoolSize = 8; internal const MsmqAuthenticationMode MsmqAuthenticationMode = System.ServiceModel.MsmqAuthenticationMode.WindowsDomain; internal const MsmqEncryptionAlgorithm MsmqEncryptionAlgorithm = System.ServiceModel.MsmqEncryptionAlgorithm.RC4Stream; - internal const MsmqSecureHashAlgorithm MsmqSecureHashAlgorithm = System.ServiceModel.MsmqSecureHashAlgorithm.Sha1; + internal const MsmqSecureHashAlgorithm DefaultMsmqSecureHashAlgorithm = System.ServiceModel.MsmqSecureHashAlgorithm.Sha256; + internal static MsmqSecureHashAlgorithm MsmqSecureHashAlgorithm { get { return LocalAppContextSwitches.UseSha1InMsmqEncryptionAlgorithm ? MsmqSecureHashAlgorithm.Sha1 : DefaultMsmqSecureHashAlgorithm; } } internal const ProtectionLevel MsmqProtectionLevel = ProtectionLevel.Sign; internal const ReceiveErrorHandling ReceiveErrorHandling = System.ServiceModel.ReceiveErrorHandling.Fault; internal const int ReceiveRetryCount = 5; @@ -202,10 +203,26 @@ namespace System.ServiceModel.Channels internal const bool RequireClientCertificate = false; internal const int MaxFaultSize = MaxBufferSize; internal const int MaxSecurityFaultSize = 16384; + + internal const SslProtocols OldDefaultSslProtocols = System.Security.Authentication.SslProtocols.Tls | + System.Security.Authentication.SslProtocols.Tls11 | + System.Security.Authentication.SslProtocols.Tls12; - internal const SslProtocols SslProtocols = System.Security.Authentication.SslProtocols.Tls | - System.Security.Authentication.SslProtocols.Tls11 | - System.Security.Authentication.SslProtocols.Tls12; + internal static SslProtocols SslProtocols + { + get + { + if (LocalAppContextSwitches.DontEnableSystemDefaultTlsVersions) + { + return OldDefaultSslProtocols; + } + else + { + // SslProtocols.None uses the default SSL protocol from the OS. + return System.Security.Authentication.SslProtocols.None; + } + } + } // Calling CreateFault on an incoming message can expose some DoS-related security // vulnerabilities when a service is in streaming mode. See MB 47592 for more details. diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs index 1ace36ecf50..c4516f07e34 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs @@ -465,6 +465,9 @@ namespace System.ServiceModel.Channels public const uint MAX_PATH = 260; + public const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + public const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; + [StructLayout(LayoutKind.Sequential)] internal class SECURITY_ATTRIBUTES { @@ -1092,6 +1095,10 @@ namespace System.ServiceModel.Channels [ResourceExposure(ResourceScope.Process)] internal static extern SafeLibraryHandle LoadLibrary(string libFilename); + [DllImport(KERNEL32, CharSet = CharSet.Auto, SetLastError = true)] + [ResourceExposure(ResourceScope.Process)] + internal static extern SafeLibraryHandle LoadLibraryEx(string lpModuleName, IntPtr hFile, uint dwFlags); + // On Vista and higher, check the value of the machine FIPS policy [DllImport(BCRYPT, SetLastError = true)] [ResourceExposure(ResourceScope.None)] @@ -1099,7 +1106,6 @@ namespace System.ServiceModel.Channels [MarshalAs(UnmanagedType.U1), Out] out bool pfEnabled ); - #if !FEATURE_CORECLR private static IntPtr GetCurrentProcessToken() { return new IntPtr(-4); } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/MsmqTransportSecurityElement.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/MsmqTransportSecurityElement.cs index 2a5ae008d75..33fdefbd855 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/MsmqTransportSecurityElement.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/MsmqTransportSecurityElement.cs @@ -40,11 +40,11 @@ namespace System.ServiceModel.Configuration set { base[ConfigurationStrings.MsmqProtectionLevel] = value; } } - [ConfigurationProperty(ConfigurationStrings.MsmqSecureHashAlgorithm, DefaultValue = MsmqDefaults.MsmqSecureHashAlgorithm)] + [ConfigurationProperty(ConfigurationStrings.MsmqSecureHashAlgorithm)] [ServiceModelEnumValidator(typeof(MsmqSecureHashAlgorithmHelper))] public MsmqSecureHashAlgorithm MsmqSecureHashAlgorithm { - get { return (MsmqSecureHashAlgorithm)base[ConfigurationStrings.MsmqSecureHashAlgorithm]; } + get { return (MsmqSecureHashAlgorithm)(base[ConfigurationStrings.MsmqSecureHashAlgorithm] ?? MsmqDefaults.MsmqSecureHashAlgorithm); } set { base[ConfigurationStrings.MsmqSecureHashAlgorithm] = value; } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/SslStreamSecurityElement.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/SslStreamSecurityElement.cs index 247bd119d7a..84fbb6718f4 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/SslStreamSecurityElement.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/SslStreamSecurityElement.cs @@ -23,7 +23,7 @@ namespace System.ServiceModel.Configuration set { base[ConfigurationStrings.RequireClientCertificate] = value; } } - [ConfigurationProperty(ConfigurationStrings.SslProtocols, DefaultValue = TransportDefaults.SslProtocols)] + [ConfigurationProperty(ConfigurationStrings.SslProtocols, DefaultValue = TransportDefaults.OldDefaultSslProtocols)] [ServiceModelEnumValidator(typeof(SslProtocolsHelper))] public SslProtocols SslProtocols { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/TcpTransportSecurityElement.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/TcpTransportSecurityElement.cs index c07d01f40a7..41bb6d428eb 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/TcpTransportSecurityElement.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/TcpTransportSecurityElement.cs @@ -40,7 +40,7 @@ namespace System.ServiceModel.Configuration private set { base[ConfigurationStrings.ExtendedProtectionPolicy] = value; } } - [ConfigurationProperty(ConfigurationStrings.SslProtocols, DefaultValue = TransportDefaults.SslProtocols)] + [ConfigurationProperty(ConfigurationStrings.SslProtocols, DefaultValue = TransportDefaults.OldDefaultSslProtocols)] [ServiceModelEnumValidator(typeof(SslProtocolsHelper))] public SslProtocols SslProtocols { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs index ced8931ddb5..f8bf5bfa063 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs @@ -12,15 +12,59 @@ namespace System.ServiceModel // in 4.6 and above. So we set DisableExplicitConnectionCloseHeader to true if running 4.5.2 or less. internal static class LocalAppContextSwitches { - private const string DisableExplicitConnectionCloseHeaderString = "Switch.System.ServiceModel.DisableExplicitConnectionCloseHeader"; - private const string AllowUnsignedToHeaderString = "Switch.System.ServiceModel.AllowUnsignedToHeader"; - private const string DisableCngCertificatesString = "Switch.System.ServiceModel.DisableCngCertificates"; + internal const string DisableExplicitConnectionCloseHeaderString = "Switch.System.ServiceModel.DisableExplicitConnectionCloseHeader"; + internal const string AllowUnsignedToHeaderString = "Switch.System.ServiceModel.AllowUnsignedToHeader"; + internal const string DisableCngCertificatesString = "Switch.System.ServiceModel.DisableCngCertificates"; internal const string DisableUsingServicePointManagerSecurityProtocolsString = "Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols"; + internal const string UseSha1InPipeConnectionGetHashAlgorithmString = "Switch.System.ServiceModel.UseSha1InPipeConnectionGetHashAlgorithm"; + internal const string DisableAddressHeaderCollectionValidationString = "Switch.System.ServiceModel.DisableAddressHeaderCollectionValidation"; + internal const string UseSha1InMsmqEncryptionAlgorithmString = "Switch.System.ServiceModel.UseSha1InMsmqEncryptionAlgorithm"; + internal const string DontEnableSystemDefaultTlsVersionsString = "Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions"; private static int disableExplicitConnectionCloseHeader; private static int allowUnsignedToHeader; private static int disableCngCertificates; private static int disableUsingServicePointManagerSecurityProtocols; + private static int useSha1InPipeConnectionGetHashAlgorithm; + private static int disableAddressHeaderCollectionValidation; + private static int useSha1InMsmqEncryptionAlgorithm; + private static int dontEnableSystemDefaultTlsVersions; + + public static bool DontEnableSystemDefaultTlsVersions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DontEnableSystemDefaultTlsVersionsString, ref dontEnableSystemDefaultTlsVersions); + } + } + + public static bool UseSha1InMsmqEncryptionAlgorithm + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(UseSha1InMsmqEncryptionAlgorithmString, ref useSha1InMsmqEncryptionAlgorithm); + } + } + + public static bool DisableAddressHeaderCollectionValidation + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisableAddressHeaderCollectionValidationString, ref disableAddressHeaderCollectionValidation); + } + } + + public static bool UseSha1InPipeConnectionGetHashAlgorithm + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(UseSha1InPipeConnectionGetHashAlgorithmString, ref useSha1InPipeConnectionGetHashAlgorithm); + } + } public static bool DisableExplicitConnectionCloseHeader { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/MsmqTransportSecurity.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/MsmqTransportSecurity.cs index 9a0f4c29098..e6a4b50d9cd 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/MsmqTransportSecurity.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/MsmqTransportSecurity.cs @@ -67,7 +67,7 @@ namespace System.ServiceModel } } - [DefaultValue(MsmqDefaults.MsmqSecureHashAlgorithm)] + [DefaultValue(MsmqDefaults.DefaultMsmqSecureHashAlgorithm)] public MsmqSecureHashAlgorithm MsmqSecureHashAlgorithm { get { return this.msmqHashAlgorithm; } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/WindowsUserNameCachingSecurityTokenAuthenticator.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/WindowsUserNameCachingSecurityTokenAuthenticator.cs index a9991a5b877..ac169b19750 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/WindowsUserNameCachingSecurityTokenAuthenticator.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/WindowsUserNameCachingSecurityTokenAuthenticator.cs @@ -22,7 +22,7 @@ namespace System.ServiceModel.Security.Tokens class LogonTokenCache : TimeBoundedCache { const int lowWaterMarkFactor = 75; - const int saltSize = 4; + const int saltSize = 256; TimeSpan cachedLogonTokenLifetime; RNGCryptoServiceProvider random; @@ -99,14 +99,14 @@ namespace System.ServiceModel.Security.Tokens public LogonToken(string userName, string password, byte[] salt, ReadOnlyCollection authorizationPolicies) { this.userName = userName; - this.passwordHash = ComputeHash(password, salt); + this.passwordHash = ComputeHMACSHA256Hash(password, salt); this.salt = salt; this.authorizationPolicies = System.IdentityModel.SecurityUtils.CloneAuthorizationPoliciesIfNecessary(authorizationPolicies); } public bool PasswordEquals(string password) { - byte[] passwordHash = ComputeHash(password, this.salt); + byte[] passwordHash = ComputeHMACSHA256Hash(password, this.salt); return CryptoHelper.IsEqual(this.passwordHash, passwordHash); } @@ -125,21 +125,11 @@ namespace System.ServiceModel.Security.Tokens System.IdentityModel.SecurityUtils.DisposeAuthorizationPoliciesIfNecessary(this.authorizationPolicies); } - static byte[] ComputeHash(string password, byte[] salt) + static byte[] ComputeHMACSHA256Hash(string password, byte[] key) { - if (String.IsNullOrEmpty(password)) + using (HMACSHA256 hmac = new HMACSHA256(key)) { - return salt; - } - byte[] bytes = Encoding.Unicode.GetBytes(password); - int saltSize = salt.Length; - for (int i = 0; i < bytes.Length; ++i) - { - bytes[i] ^= salt[i % saltSize]; - } - using (HashAlgorithm hashAlgorithm = CryptoHelper.NewSha1HashAlgorithm()) - { - return hashAlgorithm.ComputeHash(bytes); + return hmac.ComputeHash(Encoding.Unicode.GetBytes(password)); } } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/TcpTransportSecurity.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/TcpTransportSecurity.cs index cecfed85e38..e0d8ece46f2 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/TcpTransportSecurity.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/TcpTransportSecurity.cs @@ -81,7 +81,7 @@ namespace System.ServiceModel } } - [DefaultValue(TransportDefaults.SslProtocols)] + [DefaultValue(TransportDefaults.OldDefaultSslProtocols)] public SslProtocols SslProtocols { get { return this.sslProtocols; } diff --git a/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.cs b/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.cs index ba12b645410..a5a19530043 100644 --- a/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.cs +++ b/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.cs @@ -48,6 +48,9 @@ namespace System.Web.UI.Design.WebControls _databaseConnectionGroupBox.Location = new Point(13, top); _databaseConnectionGroupBox.Size = new Size(503, 124); + _radioButtonsGroupContainer.Location = new Point(0, 0); + _radioButtonsGroupContainer.Size = new Size(503, 124); + top = 0; // rest of controls in this group are positioned relative to the group box, so top resets _namedConnectionRadioButton.Location = new Point(9, top + 20); @@ -72,6 +75,7 @@ namespace System.Web.UI.Design.WebControls _containerNameComboBox.Location = new Point(13, top + 3); _containerNameComboBox.Size = new Size(502, 21); + // if any controls are added, top should be reset to _containerNameComboBox.Bottom before adding them here } @@ -85,6 +89,7 @@ namespace System.Web.UI.Design.WebControls _containerNameComboBox.TabStop = true; int tabIndex = 0; + _radioButtonsGroupContainer.TabIndex = tabIndex; _databaseConnectionGroupLabel.TabIndex = tabIndex += 10; _databaseConnectionGroupBox.TabIndex = tabIndex += 10; _namedConnectionRadioButton.TabIndex = tabIndex += 10; @@ -127,9 +132,12 @@ namespace System.Web.UI.Design.WebControls // Update the flag to track if we have text in the box _configureObjectContext.SelectConnectionStringHasValue(!String.IsNullOrEmpty(_connectionStringTextBox.Text)); - // Move the focus to the associated TextBox - _connectionStringTextBox.Select(); - _connectionStringTextBox.Select(0, _connectionStringTextBox.TextLength); + if (LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + // Move the focus to the associated TextBox + _connectionStringTextBox.Select(); + _connectionStringTextBox.Select(0, _connectionStringTextBox.TextLength); + } } } // else it's being unchecked, so that means another radio button is being checked and that handler will take care of updating the state @@ -166,8 +174,11 @@ namespace System.Web.UI.Design.WebControls // Update flag to indicate if there is a value selected in this box _configureObjectContext.SelectConnectionStringHasValue(_namedConnectionComboBox.SelectedIndex != -1); - // Move the focus to the associated ComboBox - _namedConnectionComboBox.Select(); + if (LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + // Move the focus to the associated ComboBox + _namedConnectionComboBox.Select(); + } // If there is a selected NamedConnection, validate the connection string right away // so that we can potentially select the default container name if there is one @@ -267,8 +278,11 @@ namespace System.Web.UI.Design.WebControls } else { - _connectionStringTextBox.Select(); - _connectionStringTextBox.Select(0, _connectionStringTextBox.TextLength); + if (LocalAppContextSwitches.UseLegacyAccessibilityFeatures || _connectionStringTextBox.TextLength != 0) + { + _connectionStringTextBox.Select(); + _connectionStringTextBox.Select(0, _connectionStringTextBox.TextLength); + } } } } diff --git a/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.designer.cs b/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.designer.cs index d0af6f0701c..69bcb1bd7ff 100644 --- a/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.designer.cs +++ b/mcs/class/referencesource/System.Web.Entity.Design/System/Data/WebControls/Design/EntityDataSourceConfigureObjectContextPanel.designer.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ using System.Windows.Forms; +using System.Web.UI.Design; namespace System.Web.UI.Design.WebControls { partial class EntityDataSourceConfigureObjectContextPanel @@ -44,6 +45,7 @@ namespace System.Web.UI.Design.WebControls this._connectionStringRadioButton = new System.Windows.Forms.RadioButton(); this._containerNameLabel = new System.Windows.Forms.Label(); this._containerNameComboBox = new System.Windows.Forms.ComboBox(); + this._radioButtonsGroupContainer = new System.Windows.Forms.GroupBox(); this.SuspendLayout(); this.InitializeSizes(); @@ -56,12 +58,24 @@ namespace System.Web.UI.Design.WebControls // // _databaseConnectionGroupBox // - this._databaseConnectionGroupBox.Controls.Add(this._namedConnectionRadioButton); - this._databaseConnectionGroupBox.Controls.Add(this._namedConnectionComboBox); - this._databaseConnectionGroupBox.Controls.Add(this._connectionStringRadioButton); - this._databaseConnectionGroupBox.Controls.Add(this._connectionStringTextBox); + if (LocalAppContextSwitches.UseLegacyAccessibilityFeatures) + { + this._databaseConnectionGroupBox.Controls.Add(this._namedConnectionRadioButton); + this._databaseConnectionGroupBox.Controls.Add(this._namedConnectionComboBox); + this._databaseConnectionGroupBox.Controls.Add(this._connectionStringRadioButton); + this._databaseConnectionGroupBox.Controls.Add(this._connectionStringTextBox); + } + else + { + this._databaseConnectionGroupBox.Controls.Add(this._namedConnectionComboBox); + this._databaseConnectionGroupBox.Controls.Add(this._connectionStringTextBox); + this._radioButtonsGroupContainer.Controls.Add(this._namedConnectionRadioButton); + this._radioButtonsGroupContainer.Controls.Add(this._connectionStringRadioButton); + this._databaseConnectionGroupBox.Controls.Add(this._radioButtonsGroupContainer); + } this._databaseConnectionGroupBox.Name = "_databaseConnectionGroupBox"; - this._databaseConnectionGroupBox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; + this._databaseConnectionGroupBox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; + this._radioButtonsGroupContainer.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; // // _namedConnectionRadioButton // @@ -130,6 +144,7 @@ namespace System.Web.UI.Design.WebControls private System.Windows.Forms.RadioButton _connectionStringRadioButton; private System.Windows.Forms.TextBox _connectionStringTextBox; private System.Windows.Forms.Label _containerNameLabel; - private System.Windows.Forms.ComboBox _containerNameComboBox; + private System.Windows.Forms.ComboBox _containerNameComboBox; + private System.Windows.Forms.GroupBox _radioButtonsGroupContainer; } } diff --git a/mcs/class/referencesource/System.Web/Cache/cache.cs b/mcs/class/referencesource/System.Web/Cache/cache.cs index a597396f644..1bb9b496a67 100644 --- a/mcs/class/referencesource/System.Web/Cache/cache.cs +++ b/mcs/class/referencesource/System.Web/Cache/cache.cs @@ -422,12 +422,11 @@ namespace System.Web.Caching { DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration); ObjectCache.Insert(key, value, new CacheInsertOptions() { Dependencies = dependencies, - AbsoluteExpiration = absoluteExpiration, + AbsoluteExpiration = utcAbsoluteExpiration, SlidingExpiration = slidingExpiration }); } - public void Insert( string key, object value, diff --git a/mcs/class/referencesource/System.Web/Configuration/FormsAuthPasswordFormat.cs b/mcs/class/referencesource/System.Web/Configuration/FormsAuthPasswordFormat.cs index 10f8226ddd0..148cd1d4ea0 100644 --- a/mcs/class/referencesource/System.Web/Configuration/FormsAuthPasswordFormat.cs +++ b/mcs/class/referencesource/System.Web/Configuration/FormsAuthPasswordFormat.cs @@ -15,6 +15,9 @@ namespace System.Web.Configuration { public enum FormsAuthPasswordFormat { Clear, SHA1, - MD5 + MD5, + SHA256, + SHA384, + SHA512 } } diff --git a/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesBase.cs b/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesBase.cs index e2f95210c40..4cdfdad0e96 100644 --- a/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesBase.cs +++ b/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesBase.cs @@ -139,7 +139,8 @@ namespace System.Web.Configuration { HttpCapabilitiesBase capabilities = null; // Get the config evaluator from the cached config object. - HttpCapabilitiesDefaultProvider capsbuilder = RuntimeConfig.GetConfig(request.Context).BrowserCaps; + HttpCapabilitiesDefaultProvider capsbuilder = request.Context.IsRuntimeErrorReported ? + RuntimeConfig.GetLKGConfig(request.Context).BrowserCaps : RuntimeConfig.GetConfig(request.Context).BrowserCaps; if (capsbuilder != null) { if (BrowserCapabilitiesProvider != null) { capsbuilder.BrowserCapabilitiesProvider = BrowserCapabilitiesProvider; diff --git a/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs b/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs index 344b260760a..9c9b8d93e86 100644 --- a/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs +++ b/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs @@ -61,6 +61,7 @@ namespace System.Web.Hosting { private const string _clrQuirkAppSettingsAppContextPrefix = "AppContext.SetSwitch:"; private const string _regexMatchTimeoutKey = "REGEX_DEFAULT_MATCH_TIMEOUT"; + private const string _configBuildersIgnoreLoadFailuresSwitch = "ConfigurationBuilders.IgnoreLoadFailure"; // Keep in sync with System.Configuration private static readonly StrongName _mwiV1StrongName = GetMicrosoftWebInfrastructureV1StrongName(); private static Object _applicationManagerStaticLock = new Object(); @@ -941,6 +942,8 @@ namespace System.Web.Hosting { bool requireHostExecutionContextManager = false; bool requireHostSecurityManager = false; + AppDomain.CurrentDomain.SetData(_configBuildersIgnoreLoadFailuresSwitch, true); + uncTokenConfig = appHost.GetConfigToken(); if (uncTokenConfig != IntPtr.Zero) { ictxConfig = new ImpersonationContext(uncTokenConfig); diff --git a/mcs/class/referencesource/System.Web/HttpApplication.cs b/mcs/class/referencesource/System.Web/HttpApplication.cs index 1ec9a1266c7..c50c8fea69b 100644 --- a/mcs/class/referencesource/System.Web/HttpApplication.cs +++ b/mcs/class/referencesource/System.Web/HttpApplication.cs @@ -2146,6 +2146,48 @@ namespace System.Web { return OnThreadEnterPrivate(setImpersonationContext); } + private StepInvoker _stepInvoker; + + public void OnExecuteRequestStep(Action callback) { + if (callback == null) { + throw new ArgumentNullException("callback"); + } + + if (!HttpRuntime.UseIntegratedPipeline) { + throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); + } + + if (_initSpecialCompleted && _initInternalCompleted) { + //throw if both InitSpecial and InitInternal have completed. + throw new InvalidOperationException(SR.GetString(SR.OnExecuteRequestStep_Cannot_Be_Called)); + } + + if (_stepInvoker == null) { + _stepInvoker = new StepInvoker(); + } + + var nextStep = _stepInvoker; + _stepInvoker = new StepInvoker((nextStepAction) => callback(new HttpContextWrapper(_context), nextStepAction), nextStep); + } + + private void ExecuteStepImpl(IExecutionStep step) { + if(_stepInvoker != null) { + bool stepCalled = false; + + _stepInvoker.Invoke(() => { + if (!stepCalled) { + stepCalled = true; + step.Execute(); + } + }); + + if (!stepCalled) { + step.Execute(); + } + } else { + step.Execute(); + } + } /* * Execute single step catching exceptions in a fancy way (see below) */ @@ -2158,7 +2200,7 @@ namespace System.Web { _context.BeginCancellablePeriod(); // request can be cancelled from this point try { - step.Execute(); + ExecuteStepImpl(step); } finally { _context.EndCancellablePeriod(); // request can be cancelled until this point @@ -2167,7 +2209,7 @@ namespace System.Web { _context.WaitForExceptionIfCancelled(); // wait outside of finally } else { - step.Execute(); + ExecuteStepImpl(step); } if (!step.CompletedSynchronously) { @@ -3096,9 +3138,8 @@ namespace System.Web { context.SyncContext.ProhibitVoidAsyncOperations(); try { - _endHandler(ar); - } - catch (Exception e) { + InvokeEndHandler(ar); + } catch (Exception e) { error = e; } @@ -3121,6 +3162,25 @@ namespace System.Web { } } + private void InvokeEndHandler(IAsyncResult ar) { + if (_application._stepInvoker != null) { + bool stepCalled = false; + + _application._stepInvoker.Invoke(() => { + if (!stepCalled) { + stepCalled = true; + _endHandler(ar); + } + }); + + if (!stepCalled) { + _endHandler(ar); + } + } else { + _endHandler(ar); + } + } + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] void ResumeStepsWithAssert(Exception error) { ResumeSteps(error); @@ -3379,9 +3439,8 @@ namespace System.Web { try { try { - _handler.EndProcessRequest(ar); - } - finally { + InvokeEndHandler(ar); + } finally { SuppressPostEndRequestIfNecessary(context); // In Integrated mode, generate the necessary response headers @@ -3421,6 +3480,25 @@ namespace System.Web { } } + private void InvokeEndHandler(IAsyncResult ar) { + if (_application._stepInvoker != null) { + bool stepCalled = false; + + _application._stepInvoker.Invoke(() => { + if (!stepCalled) { + stepCalled = true; + _handler.EndProcessRequest(ar); + } + }); + + if (!stepCalled) { + _handler.EndProcessRequest(ar); + } + } else { + _handler.EndProcessRequest(ar); + } + } + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] void ResumeStepsWithAssert(Exception error) { ResumeSteps(error); @@ -4365,5 +4443,31 @@ namespace System.Web { } #pragma warning restore 420 // volatile passed by reference } + + private class StepInvoker { + private Action _action; + private StepInvoker _nextStep; + + public StepInvoker() { } + + public StepInvoker(Action action, StepInvoker step) { + _action = action; + _nextStep = step; + } + + public void Invoke(Action executionStep) { + Debug.Assert(executionStep != null); + + // Call the chained nextStep. + // The ExecutionStep is garuanteed to execute in HttpApplication, + // since ExecutionStep could cause reEntry to the pipeline and + // there is only one StepInvoker instance per HttpApplication instance. + if (_action != null) { + _action(() => _nextStep.Invoke(executionStep)); + } else { + executionStep(); + } + } + } } } diff --git a/mcs/class/referencesource/System.Web/HttpContext.cs b/mcs/class/referencesource/System.Web/HttpContext.cs index d8cc4fe8eb2..4a96cc000b7 100644 --- a/mcs/class/referencesource/System.Web/HttpContext.cs +++ b/mcs/class/referencesource/System.Web/HttpContext.cs @@ -2006,6 +2006,10 @@ namespace System.Web { get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_USER_OBJECT) == FLAG_CHANGE_IN_USER_OBJECT; } } + internal bool IsRuntimeErrorReported { + get { return _runtimeErrorReported; } + } + internal bool IsSendResponseHeaders { get { return (_notificationContext.CurrentNotificationFlags & FLAG_SEND_RESPONSE_HEADERS) == FLAG_SEND_RESPONSE_HEADERS; } } diff --git a/mcs/class/referencesource/System.Web/HttpCookie.cs b/mcs/class/referencesource/System.Web/HttpCookie.cs index c5f127e60d6..f758a643bb7 100644 --- a/mcs/class/referencesource/System.Web/HttpCookie.cs +++ b/mcs/class/referencesource/System.Web/HttpCookie.cs @@ -18,6 +18,7 @@ namespace System.Web { using System.Security.Permissions; using System.Web.Configuration; using System.Web.Management; + using Util; /// @@ -336,6 +337,82 @@ namespace System.Web { } } + /// + /// Converts the specified string representation of an HTTP cookie to HttpCookie + /// + /// + /// + /// + public static bool TryParse(string input, out HttpCookie result) { + result = null; + + if (string.IsNullOrEmpty(input)) { + return false; + } + + // The substring before the first ';' is cookie-pair, with format of cookiename[=key1=val2&key2=val2&...] + int dividerIndex = input.IndexOf(';'); + string cookiePair = dividerIndex >= 0 ? input.Substring(0, dividerIndex) : input; + + HttpCookie cookie = HttpRequest.CreateCookieFromString(cookiePair.Trim()); + + // If there was no cookie name being created, stop parsing and return + if (string.IsNullOrEmpty(cookie.Name)) { + return false; + } + + // + // Parse the collections of cookie-av + // cookie-av = expires-av/max-age-av/domain-av/path-av/secure-av/httponly-av/extension-av + // https://tools.ietf.org/html/rfc6265 + + while (dividerIndex >= 0 && dividerIndex < input.Length - 1) { + int cookieAvStartIndex = dividerIndex + 1; + dividerIndex = input.IndexOf(';', cookieAvStartIndex); + string cookieAv = dividerIndex >= 0 ? input.Substring(cookieAvStartIndex, dividerIndex - cookieAvStartIndex).Trim() : input.Substring(cookieAvStartIndex).Trim(); + + int assignmentIndex = cookieAv.IndexOf('='); + string attributeName = assignmentIndex >= 0 ? cookieAv.Substring(0, assignmentIndex).Trim() : cookieAv; + string attributeValue = assignmentIndex >= 0 && assignmentIndex < cookieAv.Length - 1 ? cookieAv.Substring(assignmentIndex + 1).Trim() : null; + + // + // Parse supported cookie-av Attribute + + // + // Expires + if (StringUtil.EqualsIgnoreCase(attributeName, "Expires")) { + DateTime dt; + if (DateTime.TryParse(attributeValue, out dt)) { + cookie.Expires = dt; + } + } + // + // Domain + else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Domain")) { + cookie.Domain = attributeValue; + } + // + // Path + else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Path")) { + cookie.Path = attributeValue; + } + // + // Secure + else if (StringUtil.EqualsIgnoreCase(attributeName, "Secure")) { + cookie.Secure = true; + } + // + // HttpOnly + else if (StringUtil.EqualsIgnoreCase(attributeName, "HttpOnly")) { + cookie.HttpOnly = true; + } + } + + result = cookie; + + return true; + } + /* * Construct set-cookie header */ diff --git a/mcs/class/referencesource/System.Web/HttpResponse.cs b/mcs/class/referencesource/System.Web/HttpResponse.cs index b18ee02480d..69bc63a8366 100644 --- a/mcs/class/referencesource/System.Web/HttpResponse.cs +++ b/mcs/class/referencesource/System.Web/HttpResponse.cs @@ -2399,6 +2399,11 @@ namespace System.Web { Write(""); } else { + // VSO bug 360276 + if(HttpRuntime.UseIntegratedPipeline) { + this.ContentType = "text/html"; + } + this.StatusCode = permanent ? 301 : 302; RedirectLocation = url; // DevDivBugs 158137: 302 Redirect vulnerable to XSS @@ -3286,7 +3291,8 @@ namespace System.Web { } private String ConvertToFullyQualifiedRedirectUrlIfRequired(String url) { - HttpRuntimeSection runtimeConfig = RuntimeConfig.GetConfig(_context).HttpRuntime; + HttpRuntimeSection runtimeConfig = _context.IsRuntimeErrorReported ? + RuntimeConfig.GetLKGConfig(_context).HttpRuntime : RuntimeConfig.GetConfig(_context).HttpRuntime; if ( runtimeConfig.UseFullyQualifiedRedirectUrl || (Request != null && (string)Request.Browser["requiresFullyQualifiedRedirectUrl"] == "true")) { return (new Uri(Request.Url, url)).AbsoluteUri ; diff --git a/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs b/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs index aeb505adeab..3bf4d388bfc 100644 --- a/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs +++ b/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs @@ -81,6 +81,14 @@ namespace System.Web.Security.Cryptography { return new SHA256Cng(); } + internal static SHA384 CreateSHA384() { + return new SHA384Cng(); + } + + internal static SHA512 CreateSHA512() { + return new SHA512Cng(); + } + [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5353:TripleDESCannotBeUsed", Justification = @"This is only used by legacy code; new features do not use this algorithm.")] [Obsolete("3DES is deprecated and MUST NOT be used by new features. Consider using AES instead.")] internal static TripleDES CreateTripleDES() { diff --git a/mcs/class/referencesource/System.Web/Security/FormsAuthentication.cs b/mcs/class/referencesource/System.Web/Security/FormsAuthentication.cs index 391743621fc..e50e16e5885 100644 --- a/mcs/class/referencesource/System.Web/Security/FormsAuthentication.cs +++ b/mcs/class/referencesource/System.Web/Security/FormsAuthentication.cs @@ -63,6 +63,12 @@ namespace System.Web.Security { hashAlgorithm = CryptoAlgorithms.CreateSHA1(); else if (StringUtil.EqualsIgnoreCase(passwordFormat, "md5")) hashAlgorithm = CryptoAlgorithms.CreateMD5(); + else if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha256")) + hashAlgorithm = CryptoAlgorithms.CreateSHA256(); + else if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha384")) + hashAlgorithm = CryptoAlgorithms.CreateSHA384(); + else if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha512")) + hashAlgorithm = CryptoAlgorithms.CreateSHA512(); else throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "passwordFormat")); @@ -346,6 +352,15 @@ namespace System.Web.Security { #pragma warning disable 618 // HashPasswordForStorignInConfigFile is now obsolete switch (settings.Forms.Credentials.PasswordFormat) { + case FormsAuthPasswordFormat.SHA256: + encPassword = HashPasswordForStoringInConfigFile(password, "sha256"); + break; + case FormsAuthPasswordFormat.SHA384: + encPassword = HashPasswordForStoringInConfigFile(password, "sha384"); + break; + case FormsAuthPasswordFormat.SHA512: + encPassword = HashPasswordForStoringInConfigFile(password, "sha512"); + break; case FormsAuthPasswordFormat.SHA1: encPassword = HashPasswordForStoringInConfigFile(password, "sha1"); break; diff --git a/mcs/class/referencesource/System.Web/Security/Membership.cs b/mcs/class/referencesource/System.Web/Security/Membership.cs index dfe0be3bc65..37b91570190 100644 --- a/mcs/class/referencesource/System.Web/Security/Membership.cs +++ b/mcs/class/referencesource/System.Web/Security/Membership.cs @@ -399,6 +399,13 @@ namespace System.Web.Security { MembershipSection settings = appConfig.Membership; generalSettingsInitialized = InitializeSettings(initializeGeneralSettings, appConfig, settings); defaultProviderInitialized = InitializeDefaultProvider(initializeDefaultProvider, settings); + + // VSO #265267 log warning in event log when using clear password and encrypted password in Membership provider + // VSO #433626 In order to minimize the behavior change, we are going to read the password format from the config settings only instead of getting from the provider class + // Also allow user to opt-out this feature. + if (AppSettings.LogMembershipPasswordFormatWarning) { + CheckedPasswordFormat(settings); + } } catch (Exception e) { s_InitializeException = e; throw; @@ -412,23 +419,23 @@ namespace System.Web.Security { if (defaultProviderInitialized) { s_InitializedDefaultProvider = true; } - // VSO #265267 log warning in event log when using clear password and encrypted password in Membership provider - // VSO #366114 Move this to only after the initialization has fully completed. - if (s_Initialized && s_InitializedDefaultProvider) { - CheckedPasswordFormat(s_Providers); - } } } // VSO #265267 we want to log a warning in the event log, whenever detect using clear password or encrypted password formats settings in Membership provider - private static void CheckedPasswordFormat(MembershipProviderCollection providers) { + // VSO #433626 In order to minimize the behavior change, we are going to read the password format from the config settings only instead of getting from the provider class + private static void CheckedPasswordFormat(MembershipSection settings) { //VSO #294931 Since this is an optional feature, we want to prevent any corner cases that were not able to return the password format. In those cases, we will just do nothing and not log any warnings. try { - - foreach (MembershipProvider p in providers) { - if (p != null && (p.PasswordFormat == MembershipPasswordFormat.Clear || p.PasswordFormat == MembershipPasswordFormat.Encrypted)) { - string providerName = p.Name ?? string.Empty; - WebBaseEvent.RaiseRuntimeError(new ConfigurationErrorsException(SR.GetString(SR.MembershipPasswordFormat_Obsoleted, providerName, p.PasswordFormat)), typeof(MembershipProvider)); + if (settings != null && settings.Providers != null) { + foreach (ProviderSettings ps in settings.Providers) { + if (ps != null && ps.Parameters != null) { + string passwordFormat = ps.Parameters["passwordFormat"]; + if (StringUtil.EqualsIgnoreCase(passwordFormat, "Clear") || StringUtil.EqualsIgnoreCase(passwordFormat, "Encrypted")) { + string providerName = ps.Name ?? string.Empty; + WebBaseEvent.RaiseRuntimeError(new ConfigurationErrorsException(SR.GetString(SR.MembershipPasswordFormat_Obsoleted, providerName, passwordFormat)), typeof(MembershipProvider)); + } + } } } } diff --git a/mcs/class/referencesource/System.Web/System.Web.txt b/mcs/class/referencesource/System.Web/System.Web.txt index c7e6ceda08b..987a5ccfa8b 100644 --- a/mcs/class/referencesource/System.Web/System.Web.txt +++ b/mcs/class/referencesource/System.Web/System.Web.txt @@ -3800,3 +3800,5 @@ Request_Queue_Limit_Per_Session_Exceeded=The request queue limit of the session MembershipPasswordFormat_Obsoleted=Unsecured Passwords Format Detected. The Membership Provider that contains the unsecure passwords format is: {0}. The obsoleted password format is: {1}. For more information, see https://go.microsoft.com/fwlink/?linkid=834784. Unhandled_Monitor_Exception=An unhandled exception occurred while executing '{0}' in '{1}'. + +OnExecuteRequestStep_Cannot_Be_Called=Method OnExecuteRequestStep can only be called during HttpApplication initialization or IHttpModule initialization. \ No newline at end of file diff --git a/mcs/class/referencesource/System.Web/Util/AppSettings.cs b/mcs/class/referencesource/System.Web/Util/AppSettings.cs index d9a78e5da20..ff7b5575efd 100644 --- a/mcs/class/referencesource/System.Web/Util/AppSettings.cs +++ b/mcs/class/referencesource/System.Web/Util/AppSettings.cs @@ -133,6 +133,9 @@ namespace System.Web.Util { if (settings == null || !int.TryParse(settings["aspnet:RequestQueueLimitPerSession"], out _requestQueueLimitPerSession) || _requestQueueLimitPerSession < 0) _requestQueueLimitPerSession = BinaryCompatibility.Current.TargetsAtLeastFramework463 ? DefaultRequestQueueLimitPerSession : UnlimitedRequestsPerSession; + if (settings == null || !Boolean.TryParse(settings["aspnet:LogMembershipPasswordFormatWarning"], out _logMembershipPasswordFormatWarning)) + _logMembershipPasswordFormatWarning = true; + _settingsInitialized = true; } } @@ -506,5 +509,15 @@ namespace System.Web.Util { return _requestQueueLimitPerSession; } } + + // true [default] to log warning if password format is not secure + // false -- Not to log warning if password format is not secure + private static bool _logMembershipPasswordFormatWarning; + internal static bool LogMembershipPasswordFormatWarning { + get { + EnsureSettingsLoaded(); + return _logMembershipPasswordFormatWarning; + } + } } } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs index ddc33234132..79f7073b003 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs @@ -39,5 +39,16 @@ namespace System return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.IgnoreKindInUtcTimeSerialization", ref _ignoreKindInUtcTimeSerialization); } } + + private static int _enableTimeSpanSerialization; + + public static bool EnableTimeSpanSerialization + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.EnableTimeSpanSerialization", ref _enableTimeSpanSerialization); + } + } } } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Core/XmlConfiguration.cs b/mcs/class/referencesource/System.Xml/System/Xml/Core/XmlConfiguration.cs index 4f983ce934d..65fac336a68 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Core/XmlConfiguration.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Core/XmlConfiguration.cs @@ -14,6 +14,7 @@ namespace System.Xml.XmlConfiguration { internal const string ProhibitDefaultResolverName = "prohibitDefaultResolver"; internal const string LimitXPathComplexityName = "limitXPathComplexity"; internal const string EnableMemberAccessForXslCompiledTransformName = "enableMemberAccessForXslCompiledTransform"; + internal const string CollapseWhiteSpaceIntoEmptyStringName = "CollapseWhiteSpaceIntoEmptyString"; internal const string XmlConfigurationSectionName = "system.xml"; @@ -62,6 +63,46 @@ namespace System.Xml.XmlConfiguration { else return new XmlUrlResolver(); } + +#if CONFIGURATION_DEP + [ConfigurationProperty(XmlConfigurationString.CollapseWhiteSpaceIntoEmptyStringName, DefaultValue = "false")] +#endif + public string CollapseWhiteSpaceIntoEmptyStringString { + get { +#if CONFIGURATION_DEP + return (string)this[XmlConfigurationString.CollapseWhiteSpaceIntoEmptyStringName]; +#else + return null; +#endif + } + set { +#if CONFIGURATION_DEP + this[XmlConfigurationString.CollapseWhiteSpaceIntoEmptyStringName] = value; +#endif + } + } + + private bool _CollapseWhiteSpaceIntoEmptyString { + get { + string value = CollapseWhiteSpaceIntoEmptyStringString; + bool result; + XmlConvert.TryToBoolean(value, out result); + return result; + } + } + + //check the config every time, otherwise will have problem in different asp.net pages which have different settings. + //ConfigurationManager will cache the section result, so expect no perf issue. + internal static bool CollapseWhiteSpaceIntoEmptyString { + get { +#if CONFIGURATION_DEP + XmlReaderSection section = System.Configuration.ConfigurationManager.GetSection(XmlConfigurationString.XmlReaderSectionPath) as XmlReaderSection; + return (section != null) ? section._CollapseWhiteSpaceIntoEmptyString : false; +#else + return false; +#endif + } + } } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/CodeGenerator.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/CodeGenerator.cs index a01f38828d5..bfc07babb6a 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/CodeGenerator.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/CodeGenerator.cs @@ -1113,8 +1113,23 @@ namespace System.Xml.Serialization { case TypeCode.Empty: case TypeCode.DBNull: default: - Debug.Assert(false, "UnknownConstantType"); - throw new NotSupportedException("UnknownConstantType"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType)))); + if (valueType == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) + { + ConstructorInfo TimeSpan_ctor = typeof(TimeSpan).GetConstructor( + CodeGenerator.InstanceBindingFlags, + null, + new Type[] { typeof(Int64) }, + null + ); + Ldc(((TimeSpan)o).Ticks); // ticks + New(TimeSpan_ctor); + break; + } + else + { + Debug.Assert(false, "UnknownConstantType"); + throw new NotSupportedException("UnknownConstantType"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType)))); + } } } } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/PrimitiveXmlSerializers.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/PrimitiveXmlSerializers.cs index d2df57b8168..a41dc8f5b70 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/PrimitiveXmlSerializers.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/PrimitiveXmlSerializers.cs @@ -154,6 +154,18 @@ namespace System.Xml.Serialization { WriteElementStringRaw(@"guid", @"", System.Xml.XmlConvert.ToString((System.Guid)((System.Guid)o))); } + internal void Write_TimeSpan(object o) + { + WriteStartDocument(); + if (o == null) + { + WriteEmptyTag(@"TimeSpan", @""); + return; + } + TimeSpan timeSpan = (TimeSpan)o; + WriteElementStringRaw(@"TimeSpan", @"", System.Xml.XmlConvert.ToString(timeSpan)); + } + internal void Write_char(object o) { WriteStartDocument(); if (o == null) { @@ -489,6 +501,38 @@ namespace System.Xml.Serialization { return (object)o; } + internal object Read_TimeSpan() + { + object o = null; + Reader.MoveToContent(); + if (Reader.NodeType == System.Xml.XmlNodeType.Element) + { + if (((object)Reader.LocalName == (object)id19_TimeSpan && (object)Reader.NamespaceURI == (object)id2_Item)) + { + if (Reader.IsEmptyElement) + { + Reader.Skip(); + //For backward compatibiity + //When using old serializer, the serialized TimeSpan value is empty string + o = default(TimeSpan); + } + else + { + o = System.Xml.XmlConvert.ToTimeSpan(Reader.ReadElementString()); + } + } + else + { + throw CreateUnknownNodeException(); + } + } + else + { + UnknownNode(null); + } + return (object)o; + } + internal object Read_char() { object o = null; Reader.MoveToContent(); @@ -542,6 +586,7 @@ namespace System.Xml.Serialization { System.String id9_decimal; System.String id8_double; System.String id17_guid; + System.String id19_TimeSpan; System.String id2_Item; System.String id13_unsignedShort; System.String id18_char; @@ -563,6 +608,10 @@ namespace System.Xml.Serialization { id9_decimal = Reader.NameTable.Add(@"decimal"); id8_double = Reader.NameTable.Add(@"double"); id17_guid = Reader.NameTable.Add(@"guid"); + if (LocalAppContextSwitches.EnableTimeSpanSerialization) + { + id19_TimeSpan = Reader.NameTable.Add(@"TimeSpan"); + } id2_Item = Reader.NameTable.Add(@""); id13_unsignedShort = Reader.NameTable.Add(@"unsignedShort"); id18_char = Reader.NameTable.Add(@"char"); diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Types.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Types.cs index 103b424f9fd..5b5cad1e701 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Types.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Types.cs @@ -485,6 +485,10 @@ namespace System.Xml.Serialization { AddNonXsdPrimitive(typeof(Guid), "guid", UrtTypes.Namespace, "Guid", new XmlQualifiedName("string", XmlSchema.Namespace), new XmlSchemaFacet[] { guidPattern }, TypeFlags.CanBeAttributeValue | TypeFlags.CanBeElementValue | TypeFlags.XmlEncodingNotRequired | TypeFlags.IgnoreDefault); AddNonXsdPrimitive(typeof(char), "char", UrtTypes.Namespace, "Char", new XmlQualifiedName("unsignedShort", XmlSchema.Namespace), new XmlSchemaFacet[0], TypeFlags.CanBeAttributeValue | TypeFlags.CanBeElementValue | TypeFlags.HasCustomFormatter | TypeFlags.IgnoreDefault); + if (LocalAppContextSwitches.EnableTimeSpanSerialization) + { + AddNonXsdPrimitive(typeof(TimeSpan), "TimeSpan", UrtTypes.Namespace, "TimeSpan", new XmlQualifiedName("duration", XmlSchema.Namespace), new XmlSchemaFacet[0], TypeFlags.CanBeAttributeValue | TypeFlags.CanBeElementValue | TypeFlags.XmlEncodingNotRequired); + } AddSoapEncodedTypes(Soap.Encoding); @@ -525,6 +529,8 @@ namespace System.Xml.Serialization { return true; else if (type == typeof(Guid)) return true; + else if (LocalAppContextSwitches.EnableTimeSpanSerialization && type == typeof(TimeSpan)) + return true; else if (type == typeof(XmlNode[])) { return true; } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReader.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReader.cs index 5a3d21642d4..64be0a91128 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReader.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReader.cs @@ -113,6 +113,7 @@ namespace System.Xml.Serialization { string charID; string guidID; + string timeSpanID; static bool checkDeserializeAdvances; #if CONFIGURATION_DEP @@ -231,6 +232,10 @@ namespace System.Xml.Serialization { oldTimeInstantID = r.NameTable.Add("timeInstant"); charID = r.NameTable.Add("char"); guidID = r.NameTable.Add("guid"); + if (LocalAppContextSwitches.EnableTimeSpanSerialization) + { + timeSpanID = r.NameTable.Add("TimeSpan"); + } base64ID = r.NameTable.Add("base64"); anyURIID = r.NameTable.Add("anyURI"); @@ -658,6 +663,8 @@ namespace System.Xml.Serialization { value = ToChar(ReadStringValue()); else if ((object) type.Name == (object) guidID) value = new Guid(CollapseWhitespace(ReadStringValue())); + else if ((object)type.Name == (object)timeSpanID && LocalAppContextSwitches.EnableTimeSpanSerialization) + value = XmlConvert.ToTimeSpan(ReadStringValue()); else value = ReadXmlNodes(elementCanBeType); } @@ -749,7 +756,9 @@ namespace System.Xml.Serialization { value = default(Nullable); else if ((object) type.Name == (object) guidID) value = default(Nullable); - else + else if ((object)type.Name == (object)timeSpanID && LocalAppContextSwitches.EnableTimeSpanSerialization) + value = default(Nullable); + else value = null; } else @@ -4285,26 +4294,51 @@ namespace System.Xml.Serialization { Writer.WriteLine("{"); } Writer.Indent++; - - WriteSourceBegin(source); - if (element.Mapping.TypeDesc == QnameTypeDesc) - Writer.Write("ReadElementQualifiedName()"); - else { - string readFunc; - switch (element.Mapping.TypeDesc.FormatterName) { - case "ByteArrayBase64": - case "ByteArrayHex": - readFunc = "false"; - break; - default: - readFunc = "Reader.ReadElementString()"; - break; + //For backward compatibiity + //When using old serializer, the serialized TimeSpan value is empty string + if (element.Mapping.TypeDesc.Type == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) + { + Writer.WriteLine("if (Reader.IsEmptyElement) {"); + Writer.Indent++; + Writer.WriteLine("Reader.Skip();"); + WriteSourceBegin(source); + Writer.Write("default(System.TimeSpan)"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + Writer.Indent++; + WriteSourceBegin(source); + WritePrimitive(element.Mapping, "Reader.ReadElementString()"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + WriteSourceBegin(source); + if (element.Mapping.TypeDesc == QnameTypeDesc) + Writer.Write("ReadElementQualifiedName()"); + else { + string readFunc; + switch (element.Mapping.TypeDesc.FormatterName) { + case "ByteArrayBase64": + case "ByteArrayHex": + readFunc = "false"; + break; + default: + readFunc = "Reader.ReadElementString()"; + break; + } + WritePrimitive(element.Mapping, readFunc); } - WritePrimitive(element.Mapping, readFunc); + + WriteSourceEnd(source); + Writer.WriteLine(";"); } - WriteSourceEnd(source); - Writer.WriteLine(";"); Writer.Indent--; Writer.WriteLine("}"); } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReaderILGen.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReaderILGen.cs index 6ba4b2d7fb5..918b405d554 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReaderILGen.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationReaderILGen.cs @@ -863,6 +863,7 @@ namespace System.Xml.Serialization { else { Type argType = source == "false" ? typeof(Boolean) : typeof(String); MethodInfo ToXXX; + if (mapping.TypeDesc.HasCustomFormatter) { // Only these methods below that is non Static and need to ldarg("this") for Call. @@ -3065,34 +3066,84 @@ namespace System.Xml.Serialization { } else { } - - WriteSourceBegin(source); - if (element.Mapping.TypeDesc == QnameTypeDesc) { - MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod( - "ReadElementQualifiedName", - CodeGenerator.InstanceBindingFlags, - null, - CodeGenerator.EmptyTypeArray, - null - ); + //For backward compatibiity + //When using old serializer, the serialized TimeSpan value is empty string + if (LocalAppContextSwitches.EnableTimeSpanSerialization && element.Mapping.TypeDesc.Type == typeof(TimeSpan)) + { + MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( + "get_Reader", + CodeGenerator.InstanceBindingFlags, + null, + CodeGenerator.EmptyTypeArray, + null + ); + MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( + "get_IsEmptyElement", + CodeGenerator.InstanceBindingFlags, + null, + CodeGenerator.EmptyTypeArray, + null + ); ilg.Ldarg(0); - ilg.Call(XmlSerializationReader_ReadElementQualifiedName); + ilg.Call(XmlSerializationReader_get_Reader); + ilg.Call(XmlReader_get_IsEmptyElement); + ilg.If(); + WriteSourceBegin(source); + MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( + "Skip", + CodeGenerator.InstanceBindingFlags, + null, + CodeGenerator.EmptyTypeArray, + null + ); + ilg.Ldarg(0); + ilg.Call(XmlSerializationReader_get_Reader); + ilg.Call(XmlReader_Skip); + ConstructorInfo TimeSpan_ctor = typeof(TimeSpan).GetConstructor( + CodeGenerator.InstanceBindingFlags, + null, + new Type[] { typeof(Int64) }, + null + ); + ilg.Ldc(default(TimeSpan).Ticks); + ilg.New(TimeSpan_ctor); + WriteSourceEnd(source, element.Mapping.TypeDesc.Type); + ilg.Else(); + WriteSourceBegin(source); + WritePrimitive(element.Mapping, "Reader.ReadElementString()"); + WriteSourceEnd(source, element.Mapping.TypeDesc.Type); + ilg.EndIf(); } - else { - string readFunc; - switch (element.Mapping.TypeDesc.FormatterName) { - case "ByteArrayBase64": - case "ByteArrayHex": - readFunc = "false"; - break; - default: - readFunc = "Reader.ReadElementString()"; - break; + else + { + WriteSourceBegin(source); + if (element.Mapping.TypeDesc == QnameTypeDesc) { + MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod( + "ReadElementQualifiedName", + CodeGenerator.InstanceBindingFlags, + null, + CodeGenerator.EmptyTypeArray, + null + ); + ilg.Ldarg(0); + ilg.Call(XmlSerializationReader_ReadElementQualifiedName); + } + else { + string readFunc; + switch (element.Mapping.TypeDesc.FormatterName) { + case "ByteArrayBase64": + case "ByteArrayHex": + readFunc = "false"; + break; + default: + readFunc = "Reader.ReadElementString()"; + break; + } + WritePrimitive(element.Mapping, readFunc); } - WritePrimitive(element.Mapping, readFunc); + WriteSourceEnd(source, element.Mapping.TypeDesc.Type); } - - WriteSourceEnd(source, element.Mapping.TypeDesc.Type); + if (doEndIf) ilg.EndIf(); } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationWriter.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationWriter.cs index d15b2bf9bf5..fbb68887593 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationWriter.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializationWriter.cs @@ -197,17 +197,19 @@ namespace System.Xml.Serialization { typeNs = UrtTypes.Namespace; break; default: - if (type == typeof(XmlQualifiedName)) typeName = "QName"; - else if (type == typeof(byte[])) typeName = "base64Binary"; - else if (type == typeof(Guid)) { - typeName = "guid"; - typeNs = UrtTypes.Namespace; - } - else if (type == typeof(XmlNode[])){ - typeName = Soap.UrType; - } - else - return null; + if (type == typeof(XmlQualifiedName)) typeName = "QName"; + else if (type == typeof(byte[])) typeName = "base64Binary"; + else if (type == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) + typeName = "TimeSpan"; + else if (type == typeof(Guid)) { + typeName = "guid"; + typeNs = UrtTypes.Namespace; + } + else if (type == typeof(XmlNode[])) { + typeName = Soap.UrType; + } + else + return null; break; } return new XmlQualifiedName(typeName, typeNs); @@ -309,6 +311,10 @@ namespace System.Xml.Serialization { type = "guid"; typeNs = UrtTypes.Namespace; } + else if (t == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) { + value = XmlConvert.ToString((TimeSpan)o); + type = "TimeSpan"; + } else if (typeof(XmlNode[]).IsAssignableFrom(t)){ if (name == null) w.WriteStartElement(Soap.UrType, XmlSchema.Namespace); @@ -3113,6 +3119,13 @@ namespace System.Xml.Serialization { if (type.IsEnum) { Writer.Write(((int)value).ToString(null, NumberFormatInfo.InvariantInfo)); } + else if(type == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) { + Writer.Write(" new "); + Writer.Write(type.FullName); + Writer.Write("("); + Writer.Write(((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture)); + Writer.Write(")"); + } else { throw new InvalidOperationException(Res.GetString(Res.XmlUnsupportedDefaultType, type.FullName)); } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializer.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializer.cs index eb11fe3b372..75d99bf2924 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializer.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/XmlSerializer.cs @@ -793,6 +793,9 @@ namespace System.Xml.Serialization { else if (primitiveType == typeof(Guid)) { writer.Write_guid(o); } + else if (primitiveType == typeof(TimeSpan)) { + writer.Write_TimeSpan(o); + } else { throw new InvalidOperationException(Res.GetString(Res.XmlUnxpectedType, primitiveType.FullName)); } @@ -853,17 +856,20 @@ namespace System.Xml.Serialization { default: if (primitiveType == typeof(XmlQualifiedName)) { - o = reader.Read_QName(); - } + o = reader.Read_QName(); + } else if (primitiveType == typeof(byte[])) { - o = reader.Read_base64Binary(); - } + o = reader.Read_base64Binary(); + } else if (primitiveType == typeof(Guid)) { - o = reader.Read_guid(); - } + o = reader.Read_guid(); + } + else if (primitiveType == typeof(TimeSpan) && LocalAppContextSwitches.EnableTimeSpanSerialization) { + o = reader.Read_TimeSpan(); + } else { - throw new InvalidOperationException(Res.GetString(Res.XmlUnxpectedType, primitiveType.FullName)); - } + throw new InvalidOperationException(Res.GetString(Res.XmlUnxpectedType, primitiveType.FullName)); + } break; } return o; diff --git a/mcs/class/referencesource/System.Xml/System/Xml/XmlComplianceUtil.cs b/mcs/class/referencesource/System.Xml/System/Xml/XmlComplianceUtil.cs index c30f7263e52..e04876479bf 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/XmlComplianceUtil.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/XmlComplianceUtil.cs @@ -28,7 +28,7 @@ namespace System.Xml { while ( xmlCharType.IsWhiteSpace( value[startPos] ) ) { startPos++; if ( startPos == len ) { - return " "; + return (System.Xml.XmlConfiguration.XmlReaderSection.CollapseWhiteSpaceIntoEmptyString)?"":" "; } } diff --git a/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs b/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs index 1bf3586fe47..caaa20be1c2 100644 --- a/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs +++ b/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs @@ -433,7 +433,7 @@ namespace Microsoft.Win32 { internal byte Reserved = 0; } - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential)] internal struct SYSTEM_INFO { internal int dwOemId; // This is a union of a DWORD and a struct containing 2 WORDs. internal int dwPageSize; @@ -2741,7 +2741,6 @@ namespace Microsoft.Win32 { [ResourceExposure(ResourceScope.None)] internal static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum, IApplicationContext pAppCtx, IAssemblyName pName, uint dwFlags, IntPtr pvReserved); #endif // FEATURE_FUSION - #if FEATURE_CORECLR [DllImport(KERNEL32, CharSet=CharSet.Unicode)] [SuppressUnmanagedCodeSecurityAttribute()] @@ -2769,5 +2768,35 @@ namespace Microsoft.Win32 { [DllImport(KERNEL32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal extern static bool QueryUnbiasedInterruptTime(out ulong UnbiasedTime); + +// This is needed by the RuntimeInformation feature + [DllImport(NTDLL)] + internal static extern int RtlGetVersion(out RTL_OSVERSIONINFOEX lpVersionInformation); + + [StructLayout(LayoutKind.Sequential)] + internal struct RTL_OSVERSIONINFOEX + { + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + internal string szCSDVersion; + } + + [DllImport(KERNEL32)] + internal extern static void GetNativeSystemInfo(out SYSTEM_INFO lpSystemInfo); + + internal enum ProcessorArchitecture : ushort + { + Processor_Architecture_INTEL = 0, + Processor_Architecture_ARM = 5, + Processor_Architecture_IA64 = 6, + Processor_Architecture_AMD64 = 9, + Processor_Architecture_ARM64 = 12, + Processor_Architecture_UNKNOWN = 0xFFFF + } +// end RuntimeInformation } } diff --git a/mcs/class/referencesource/mscorlib/mscorlib.txt b/mcs/class/referencesource/mscorlib/mscorlib.txt index 35fac908aaa..d60a17c3bbe 100644 --- a/mcs/class/referencesource/mscorlib/mscorlib.txt +++ b/mcs/class/referencesource/mscorlib/mscorlib.txt @@ -3625,3 +3625,12 @@ Globalization.cp_57011 = ISCII Punjabi ArgumentException_ValueTupleIncorrectType=Argument must be of type {0}. ArgumentException_ValueTupleLastArgumentNotAValueTuple=The last element of an eight element ValueTuple must be a ValueTuple. +; ThreadPoolBoundHandle +Argument_PreAllocatedAlreadyAllocated='preAllocated' is already in use. +InvalidOperation_NativeOverlappedReused=NativeOverlapped cannot be reused for multiple operations. +Argument_NativeOverlappedAlreadyFree='overlapped' has already been freed. +Argument_AlreadyBoundOrSyncHandle='handle' has already been bound to the thread pool, or was not opened for asynchronous I/O. +Argument_NativeOverlappedWrongBoundHandle='overlapped' was not allocated by this ThreadPoolBoundHandle instance. + +; RuntimeInformation +Argument_EmptyValue=Value cannot be empty. \ No newline at end of file diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.DesktopOverrides.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.DesktopOverrides.cs index 2b5055ddc97..1f5434cc985 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.DesktopOverrides.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.DesktopOverrides.cs @@ -136,7 +136,7 @@ namespace System if (Win32Native.RegOpenKeyEx(hklm, REG_KEY_APPCONTEXT, 0, Win32Native.KEY_READ, out hkey) == 0) { - int size = 6; // "false".Length+1 + int size = 6 * sizeof(char); // "false".Length+1 * sizeof (char) as the API expects byte count and not char count. int type = 0; System.Text.StringBuilder keyBuffer = new System.Text.StringBuilder((int)size); if (Win32Native.RegQueryValueEx(hkey, switchName, null, ref type, keyBuffer, ref size) == 0) diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventproviderbase.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventproviderbase.cs deleted file mode 100644 index b1b7786df7e..00000000000 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventproviderbase.cs +++ /dev/null @@ -1,4375 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved -// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in. -// It is available from http://www.codeplex.com/hyperAddin -#define FEATURE_MANAGED_ETW - -#if !FEATURE_CORECLR || FEATURE_NETCORE -#define FEATURE_ACTIVITYSAMPLING -#endif // !FEATURE_CORECLR || FEATURE_NETCORE - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Globalization; -using System.Reflection; -using System.Resources; -using System.Security; -using System.Security.Permissions; -using System.Text; -using System.Threading; -using Microsoft.Win32; - -namespace System.Diagnostics.Tracing -{ - /// - /// This class is meant to be inherited by a user eventSource (which provides specific events and then - /// calls code:EventSource.WriteEvent to log them). - /// - /// sealed class MinimalEventSource : EventSource - /// { - /// * public void Load(long ImageBase, string Name) { WriteEvent(1, ImageBase, Name); } - /// * public void Unload(long ImageBase) { WriteEvent(2, ImageBase); } - /// * private MinimalEventSource() {} - /// } - /// - /// This functionaity is sufficient for many users. When more control is needed over the ETW manifest - /// that is created, that can be done by adding [Event] attributes on the methods. - /// - /// Finally for very advanced EventSources, it is possible to intercept the commands being given to the - /// eventSource and change what filtering is done (or cause actions to be performed by the eventSource (eg - /// dumping a data structure). - /// - /// The eventSources can be turned on with Window ETW controllers (eg logman), immediately. It is also - /// possible to control and intercept the data dispatcher programatically. We code:EventListener for - /// more. - /// - public class EventSource : IDisposable - { - /// - /// The human-friendly name of the eventSource. It defaults to the simple name of the class - /// - public string Name { get { return m_name; } } - /// - /// Every eventSource is assigned a GUID to uniquely identify it to the system. - /// - public Guid Guid { get { return m_guid; } } - - /// - /// Returns true if the eventSource has been enabled at all. - /// - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] -#if !FEATURE_CORECLR - [System.Runtime.TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] -#endif - public bool IsEnabled() - { - return m_eventSourceEnabled; - } - /// - /// Returns true if events with >= 'level' and have one of 'keywords' set are enabled. - /// - /// Note that the result of this function only an approximiation on whether a particular - /// event is active or not. It is only meant to be used as way of avoiding expensive - /// computation for logging when logging is not on, therefore it sometimes returns false - // positives (but is always accurate when returning false). EventSources are free to - /// have additional filtering. - /// - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - public bool IsEnabled(EventLevel level, EventKeywords keywords) - { - if (!m_eventSourceEnabled) - return false; - if (m_level != 0 && m_level < level) - return false; - if (m_matchAnyKeyword != 0 && (keywords & m_matchAnyKeyword) == 0) - return false; - -#if !FEATURE_ACTIVITYSAMPLING - - return true; - -#else // FEATURE_ACTIVITYSAMPLING - - return true; - -#if OPTIMIZE_IS_ENABLED - //================================================================================ - // 2013/03/06 - The code below is a possible optimization for IsEnabled(level, kwd) - // in case activity tracing/sampling is enabled. The added complexity of this - // code however weighs against having it "on" until we know it's really needed. - // For now we'll have this #ifdef-ed out in case we see evidence this is needed. - //================================================================================ - - // At this point we believe the event is enabled, however we now need to check - // if we filter because of activity - - // Optimization, all activity filters also register a delegate here, so if there - // is no delegate, we know there are no activity filters, which means that there - // is no additional filtering, which means that we can return true immediately. - if (s_activityDying == null) - return true; - - // if there's at least one legacy ETW listener we can't filter this - if (m_legacySessions != null && m_legacySessions.Count > 0) - return true; - - // if any event ID that triggers a new activity, or "transfers" activities - // is covered by 'keywords' we can't filter this - if (((long)keywords & m_keywordTriggers) != 0) - return true; - - // See if all listeners have activity filters that would block the event. - for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId) - { - EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId]; - if (etwSession == null) - continue; - - ActivityFilter activityFilter = etwSession.m_activityFilter; - if (activityFilter == null || - ActivityFilter.GetFilter(activityFilter, this) == null) - { - // No activity filter for ETW, if event is active for ETW, we can't filter. - for (int i = 0; i < m_eventData.Length; i++) - if (m_eventData[i].EnabledForETW) - return true; - } - else if (ActivityFilter.IsCurrentActivityActive(activityFilter)) - return true; - } - - // for regular event listeners - var curDispatcher = m_Dispatchers; - while (curDispatcher != null) - { - ActivityFilter activityFilter = curDispatcher.m_Listener.m_activityFilter; - if (activityFilter == null) - { - // See if any event is enabled. - for (int i = 0; i < curDispatcher.m_EventEnabled.Length; i++) - if (curDispatcher.m_EventEnabled[i]) - return true; - } - else if (ActivityFilter.IsCurrentActivityActive(activityFilter)) - return true; - curDispatcher = curDispatcher.m_Next; - } - - // Every listener has an activity filter that is blocking writing the event, - // thus the event is not enabled. - return false; -#endif // OPTIMIZE_IS_ENABLED - -#endif // FEATURE_ACTIVITYSAMPLING - } - - // Manifest support - /// - /// Returns the GUID that uniquely identifies the eventSource defined by 'eventSourceType'. - /// This API allows you to compute this without actually creating an instance of the EventSource. - /// It only needs to reflect over the type. - /// - public static Guid GetGuid(Type eventSourceType) - { - if (eventSourceType == null) - throw new ArgumentNullException("eventSourceType"); - Contract.EndContractBlock(); - - EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute)); - string name = eventSourceType.Name; - if (attrib != null) - { - if (attrib.Guid != null) - { - Guid g = Guid.Empty; - if(Guid.TryParse(attrib.Guid, out g)) - return g; - } - - if (attrib.Name != null) - name = attrib.Name; - } - - if (name == null) - throw new ArgumentException("eventSourceType", Environment.GetResourceString("Argument_InvalidTypeName")); - - return GenerateGuidFromName(name.ToUpperInvariant()); // Make it case insensitive. - } - /// - /// Returns the official ETW Provider name for the eventSource defined by 'eventSourceType'. - /// This API allows you to compute this without actually creating an instance of the EventSource. - /// It only needs to reflect over the type. - /// - public static string GetName(Type eventSourceType) - { - if (eventSourceType == null) - throw new ArgumentNullException("eventSourceType"); - Contract.EndContractBlock(); - - EventSourceAttribute attrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute)); - if (attrib != null && attrib.Name != null) - return attrib.Name; - - return eventSourceType.Name; - } - /// - /// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is - /// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx - /// - /// The manifest XML fragment contains the string name of the DLL name in - /// which it is embeded. This parameter spcifies what name will be used - /// The XML data string - public static string GenerateManifest(Type eventSourceType, string assemblyPathToIncludeInManifest) - { - if (eventSourceType == null) - throw new ArgumentNullException("eventSourceType"); - Contract.EndContractBlock(); - - byte[] manifestBytes = EventSource.CreateManifestAndDescriptors(eventSourceType, assemblyPathToIncludeInManifest, null); - return Encoding.UTF8.GetString(manifestBytes); - } - - // EventListener support - /// - /// returns a list (IEnumerable) of all sources in the appdomain). EventListners typically need this. - /// - /// - public static IEnumerable GetSources() - { - var ret = new List(); - lock (EventListener.EventListenersLock) - { - foreach (WeakReference eventSourceRef in EventListener.s_EventSources) - { - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource != null) - ret.Add(eventSource); - } - } - return ret; - } - - /// - /// Send a command to a particular EventSource identified by 'eventSource' - /// - /// Calling this routine simply forwards the command to the EventSource.OnEventCommand - /// callback. What the EventSource does with the command and its arguments are from that point - /// EventSource-specific. - /// - /// The eventSource is passed the EventListener that issued the command along with the command and - /// arguments. The contract is that to the extent possible the eventSource should not affect other - /// EventListeners (eg filtering events), however sometimes this simply is not possible (if the - /// command was to provoke a GC, or a System flush etc). - /// - public static void SendCommand(EventSource eventSource, EventCommand command, IDictionary commandArguments) - { - if (eventSource == null) - throw new ArgumentNullException("eventSource"); - - // User-defined EventCommands should not conflict with the reserved commands. - if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest) - throw new ArgumentException("Invalid command value.", "command"); - - eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments); - } - - // ActivityID support (see also WriteEventWithRelatedActivityIdCore) - /// - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. This API - /// should be used when the caller knows the thread's current activity (the one being - /// overwritten) has completed. Otherwise, callers should prefer the overload that - /// return the oldActivityThatWillContinue (below). - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// - /// A Guid that represents the new activity with which to mark - /// the current thread - [System.Security.SecuritySafeCritical] - public static void SetCurrentThreadActivityId(Guid activityId) - { -#if FEATURE_ACTIVITYSAMPLING - Guid newId = activityId; -#endif // FEATURE_ACTIVITYSAMPLING - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. - if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref activityId) == 0) - { -#if FEATURE_ACTIVITYSAMPLING - var activityDying = s_activityDying; - if (activityDying != null && newId != activityId) - { - if (activityId == Guid.Empty) - { - activityId = FallbackActivityId; - } - // OutputDebugString(string.Format("Activity dying: {0} -> {1}", activityId, newId)); - activityDying(activityId); // This is actually the OLD activity ID. - } -#endif // FEATURE_ACTIVITYSAMPLING - } - } - - /// - /// When a thread starts work that is on behalf of 'something else' (typically another - /// thread or network request) it should mark the thread as working on that other work. - /// This API marks the current thread as working on activity 'activityID'. It returns - /// whatever activity the thread was previously marked with. There is a convention that - /// callers can assume that callees restore this activity mark before the callee returns. - /// To encourage this this API returns the old activity, so that it can be restored later. - /// - /// All events created with the EventSource on this thread are also tagged with the - /// activity ID of the thread. - /// - /// It is common, and good practice after setting the thread to an activity to log an event - /// with a 'start' opcode to indicate that precise time/thread where the new activity - /// started. - /// - /// A Guid that represents the new activity with which to mark - /// the current thread - /// The Guid that represents the current activity - /// which will continue at some point in the future, on the current thread - [System.Security.SecuritySafeCritical] - public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) - { - oldActivityThatWillContinue = activityId; - // We ignore errors to keep with the convention that EventSources do not throw errors. - // Note we can't access m_throwOnWrites because this is a static method. - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, - ref oldActivityThatWillContinue); - // We don't call the activityDying callback here because the caller has declared that - // it is not dying. - - } - public static Guid CurrentThreadActivityId - { - [System.Security.SecurityCritical] - get - { - // We ignore errors to keep with the convention that EventSources do not throw - // errors. Note we can't access m_throwOnWrites because this is a static method. - Guid retVal = new Guid(); - UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( - UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_ID, - ref retVal); - return retVal; - } - } - - /// - /// This property allows EventSource code to appropriately handle as "different" - /// activities started on different threads that have not had an activity created on them. - /// - internal static Guid InternalCurrentThreadActivityId - { - [System.Security.SecurityCritical] - get - { - Guid retval = CurrentThreadActivityId; - if (retval == Guid.Empty) - { - retval = FallbackActivityId; - } - return retval; - } - } - - internal static Guid FallbackActivityId - { - [System.Security.SecurityCritical] - get - { -#pragma warning disable 612, 618 - // Managed thread IDs are more aggressively re-used than native thread IDs, - // so we'll use the latter... - return new Guid((uint) AppDomain.GetCurrentThreadId(), - (ushort) s_currentPid, (ushort) (s_currentPid >> 16), - 0x94, 0x1b, 0x87, 0xd5, 0xa6, 0x5c, 0x36, 0x64); -#pragma warning restore 612, 618 - } - } - - // Error APIs. (We don't throw by default, but you can probe for status) - /// - /// Because - /// - /// 1) Logging is often optional and thus should not generate fatal errors (exceptions) - /// 2) EventSources are often initialized in class constructors (which propagate exceptions poorly) - /// - /// The event source constructor does not throw exceptions. Instead we remember any exception that - /// was generated (it is also logged to Trace.WriteLine). - /// - public Exception ConstructionException { get { return m_constructionException; } } - - /// - /// Displays thew name and GUID for the eventSoruce for debugging purposes. - /// - public override string ToString() { return Environment.GetResourceString("EventSource_ToString", Name, Guid); } - - #region protected - /// - /// This is the consturctor that most users will use to create their eventSource. It takes - /// no parameters. The ETW provider name and GUID of the EventSource are determined by the EventSource - /// custom attribute (so you can determine these things declaratively). If the GUID for the eventSource - /// is not specified in the EventSourceAttribute (recommended), it is Generated by hashing the name. - /// If the ETW provider name of the EventSource is not given, the name of the EventSource class is used as - /// the ETW provider name. - /// - protected EventSource() - : this(false) - { - } - - /// - /// By default calling the 'WriteEvent' methods do NOT throw on errors (they silently discard the event). - /// This is because in most cases users assume logging is not 'precious' and do NOT wish to have logging falures - /// crash the program. However for those applications where logging is 'precious' and if it fails the caller - /// wishes to react, setting 'throwOnEventWriteErrors' will cause an exception to be thrown if WriteEvent - /// fails. Note the fact that EventWrite succeeds does not necessarily mean that the event reached its destination - /// only that operation of writing it did not fail. - /// - protected EventSource(bool throwOnEventWriteErrors) - { - m_throwOnEventWriteErrors = throwOnEventWriteErrors; - try - { - Contract.Assert(m_lastCommandException == null); - var myType = this.GetType(); - Initialize(GetGuid(myType), GetName(myType)); - m_constructionException = m_lastCommandException; - } - catch (Exception e) - { - Contract.Assert(m_eventData == null && m_eventSourceEnabled == false); - ReportOutOfBandMessage("ERROR: Exception during construction of EventSource " + Name + ": " - + e.Message, false); - m_eventSourceEnabled = false; // This is insurance, it should still be off. - if (m_lastCommandException != null) - m_constructionException = m_lastCommandException; - else - m_constructionException = e; - } - } - - // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use - // to prevent the working set hit from looking at the custom attributes on the type to get the Guid. - internal EventSource(Guid eventSourceGuid, string eventSourceName) - { - Initialize(eventSourceGuid, eventSourceName); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "guid")] - [SecuritySafeCritical] - private void Initialize(Guid eventSourceGuid, string eventSourceName) - { - if (eventSourceGuid == Guid.Empty) - { - throw new ArgumentException(Environment.GetResourceString("EventSource_NeedGuid")); - } - - if (eventSourceName == null) - { - throw new ArgumentException(Environment.GetResourceString("EventSource_NeedName")); - } - - m_name = eventSourceName; - m_guid = eventSourceGuid; -#if FEATURE_ACTIVITYSAMPLING - m_curLiveSessions = new SessionMask(0); - m_etwSessionIdMap = new EtwSession[SessionMask.MAX]; -#endif // FEATURE_ACTIVITYSAMPLING - -#if FEATURE_MANAGED_ETW - m_provider = new OverideEventProvider(this); - - try - { - m_provider.Register(eventSourceGuid); - } - catch (ArgumentException) - { - // Failed to register. Don't crash the app, just don't write events to ETW. - m_provider = null; - } -#endif - // Add the eventSource to the global (weak) list. This also sets m_id, which is the - // index in the list. - EventListener.AddEventSource(this); - - // We are logically completely initialized at this point. - m_completelyInited = true; - - // report any possible errors - ReportOutOfBandMessage(null, true); - -#if FEATURE_ACTIVITYSAMPLING - // we cue sending sampling info here based on whether we had to defer sending - // the manifest - // note: we do *not* send sampling info to any EventListeners because - // the following common code pattern would cause an AV: - // class MyEventSource: EventSource - // { - // public static EventSource Log; - // } - // class MyEventListener: EventListener - // { - // protected override void OnEventWritten(...) - // { MyEventSource.Log.anything; } <-- AV, as the static Log was not set yet - // } - if (m_eventSourceEnabled && m_deferedSendManifest) - ReportActivitySamplingInfo(null, m_curLiveSessions); -#endif // FEATURE_ACTIVITYSAMPLING - - // If we are active and we have not sent our manifest, do so now. - if (m_eventSourceEnabled && m_deferedSendManifest) - SendManifest(m_rawManifest); - } - - /// - /// This method is called when the eventSource is updated by the controller. - /// - protected virtual void OnEventCommand(EventCommandEventArgs command) { } - - internal void WriteString(string msg, SessionMask m) - { - if (m_eventSourceEnabled) - { - WriteEventString(0, (long) m.ToEventKeywords(), msg); - WriteStringToAllListeners(msg); - } - } - internal void WriteString(string msg) - { - WriteString(msg, SessionMask.All); - } - - internal void WriteStringToListener(EventListener listener, string msg, SessionMask m) - { - Contract.Assert(listener == null || (uint)m == (uint)SessionMask.FromId(0)); - - if (m_eventSourceEnabled) - { - if (listener == null) - { - WriteEventString(0, (long) m.ToEventKeywords(), msg); - } - else - { - List arg = new List(); - arg.Add(msg); - EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); - eventCallbackArgs.EventId = 0; - eventCallbackArgs.Payload = new ReadOnlyCollection(arg); - listener.OnEventWritten(eventCallbackArgs); - } - } - } - - // optimized for common signatures (no args) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId) - { - WriteEventCore(eventId, 0, null); - } - - // optimized for common signatures (ints) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, int arg1) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[1]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 4; - WriteEventCore(eventId, 1, descrs); - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, int arg1, int arg2) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[2]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 4; - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 4; - WriteEventCore(eventId, 2, descrs); - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[3]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 4; - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 4; - descrs[2].DataPointer = (IntPtr)(&arg3); - descrs[2].Size = 4; - WriteEventCore(eventId, 3, descrs); - } - } - - // optimized for common signatures (longs) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, long arg1) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[1]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 8; - WriteEventCore(eventId, 1, descrs); - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, long arg1, long arg2) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[2]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 8; - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 8; - WriteEventCore(eventId, 2, descrs); - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, long arg1, long arg2, long arg3) - { - if (m_eventSourceEnabled) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[3]; - descrs[0].DataPointer = (IntPtr)(&arg1); - descrs[0].Size = 8; - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 8; - descrs[2].DataPointer = (IntPtr)(&arg3); - descrs[2].Size = 8; - WriteEventCore(eventId, 3, descrs); - } - } - - // optimized for common signatures (strings) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - fixed (char* string1Bytes = arg1) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[1]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - WriteEventCore(eventId, 1, descrs); - } - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1, string arg2) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - if (arg2 == null) arg2 = ""; - fixed (char* string1Bytes = arg1) - fixed (char* string2Bytes = arg2) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[2]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - descrs[1].DataPointer = (IntPtr)string2Bytes; - descrs[1].Size = ((arg2.Length + 1) * 2); - WriteEventCore(eventId, 2, descrs); - } - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1, string arg2, string arg3) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - if (arg2 == null) arg2 = ""; - if (arg3 == null) arg3 = ""; - fixed (char* string1Bytes = arg1) - fixed (char* string2Bytes = arg2) - fixed (char* string3Bytes = arg3) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[3]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - descrs[1].DataPointer = (IntPtr)string2Bytes; - descrs[1].Size = ((arg2.Length + 1) * 2); - descrs[2].DataPointer = (IntPtr)string3Bytes; - descrs[2].Size = ((arg3.Length + 1) * 2); - WriteEventCore(eventId, 3, descrs); - } - } - } - - // optimized for common signatures (string and ints) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1, int arg2) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - fixed (char* string1Bytes = arg1) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[2]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 4; - WriteEventCore(eventId, 2, descrs); - } - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1, int arg2, int arg3) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - fixed (char* string1Bytes = arg1) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[3]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 4; - descrs[2].DataPointer = (IntPtr)(&arg3); - descrs[2].Size = 4; - WriteEventCore(eventId, 3, descrs); - } - } - } - - // optimized for common signatures (string and longs) - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, string arg1, long arg2) - { - if (m_eventSourceEnabled) - { - if (arg1 == null) arg1 = ""; - fixed (char* string1Bytes = arg1) - { - EventSource.EventData* descrs = stackalloc EventSource.EventData[2]; - descrs[0].DataPointer = (IntPtr)string1Bytes; - descrs[0].Size = ((arg1.Length + 1) * 2); - descrs[1].DataPointer = (IntPtr)(&arg2); - descrs[1].Size = 8; - WriteEventCore(eventId, 2, descrs); - } - } - } - - protected internal struct EventData - { - public IntPtr DataPointer { get { return (IntPtr)m_Ptr; } set { m_Ptr = (long)value; } } - public int Size { get { return m_Size; } set { m_Size = value; } } - - #region private - //Important, we pass this structure directly to the Win32 EventWrite API, so this structure must be layed out exactly - // the way EventWrite wants it. - private long m_Ptr; - private int m_Size; - internal int m_Reserved; // Used to pad the size to match the Win32 API - #endregion - } - - /// - /// This routine allows you to create efficient WriteEvent helpers, however the code that you use to - /// do this while straightfoward is unsafe. See the bodies of the WriteEvent helpers above for its use. - /// - [SecurityCritical] - [CLSCompliant(false)] - protected unsafe void WriteEventCore(int eventId, int eventDataCount, EventSource.EventData* data) - { - WriteEventWithRelatedActivityIdCore(eventId, null, eventDataCount, data); - } - - /// - /// This routine allows you to create efficient WriteEventCreatingChildActivity helpers, however the code - /// that you use to do this while straightfoward is unsafe. See the bodies of the WriteEvent helpers above - /// for its use. The only difference is that you pass the ChildAcivityID from caller through to this API - /// - [SecurityCritical] - [CLSCompliant(false)] - protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) - { - if (m_eventSourceEnabled) - { - Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. - if (childActivityID != null) - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); - -#if FEATURE_MANAGED_ETW - if (m_eventData[eventId].EnabledForETW) - { -#if FEATURE_ACTIVITYSAMPLING - // this code should be kept in [....] with WriteEventVarargs(). - SessionMask etwSessions = SessionMask.All; - // only compute etwSessions if there are *any* ETW filters enabled... - if ((ulong)m_curLiveSessions != 0) - etwSessions = GetEtwSessionMask(eventId, childActivityID); - // OutputDebugString(string.Format("{0}.WriteEvent(id {1}) -> to sessions {2:x}", - // m_name, m_eventData[eventId].Name, (ulong) etwSessions)); - - if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0) - { - if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions)) - { - // OutputDebugString(string.Format(" (1) id {0}, kwd {1:x}", - // m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Keywords)); - // by default the Descriptor.Keyword will have the perEventSourceSessionId bit - // mask set to 0x0f so, when all ETW sessions want the event we don't need to - // synthesize a new one - if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, childActivityID, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); - } - else - { - long origKwd = (long)((ulong) m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())); - // OutputDebugString(string.Format(" (2) id {0}, kwd {1:x}", - // m_eventData[eventId].Name, etwSessions.ToEventKeywords() | (ulong) origKwd)); - // only some of the ETW sessions will receive this event. Synthesize a new - // Descriptor whose Keywords field will have the appropriate bits set. - // etwSessions might be 0, if there are legacy ETW listeners that want this event - var desc = new System.Diagnostics.Tracing.EventDescriptor( - m_eventData[eventId].Descriptor.EventId, - m_eventData[eventId].Descriptor.Version, - m_eventData[eventId].Descriptor.Channel, - m_eventData[eventId].Descriptor.Level, - m_eventData[eventId].Descriptor.Opcode, - m_eventData[eventId].Descriptor.Task, - (long) etwSessions.ToEventKeywords() | origKwd); - - if (!m_provider.WriteEvent(ref desc, childActivityID, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); - } - } -#else - if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, childActivityID, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); -#endif // FEATURE_ACTIVITYSAMPLING - } -#endif - if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener) - WriteToAllListeners(eventId, childActivityID, eventDataCount, data); - } - } - - // fallback varags helpers. - /// - /// This is the varargs helper for writing an event. It does create an array and box all the arguments so it is - /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If you - /// rates are fast than that you should be used WriteEventCore to create fast helpers for your particular method - /// signature. Even if you use this for rare evnets, this call should be guarded by a 'IsEnabled()' check so that - /// the varargs call is not made when the EventSource is not active. - /// - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - protected unsafe void WriteEvent(int eventId, params object[] args) - { - WriteEventVarargs(eventId, null, args); - } - - /// - /// This is the varargs helper for writing an event which also creates a child activity. It is completely ----ygous - /// to cooresponding WriteEvent (they share implementation). It does create an array and box all the arguments so it is - /// relatively inefficient and should only be used for relatively rare events (e.g. less than 100 / sec). If you - /// rates are fast than that you should be used WriteEventCore to create fast helpers for your particular method - /// signature. Even if you use this for rare evnets, this call should be guarded by a 'IsEnabled()' check so that - /// the varargs call is not made when the EventSource is not active. - /// - [SecuritySafeCritical] - protected unsafe void WriteEventWithRelatedActivityId(int eventId, Guid childActivityID, params object[] args) - { - WriteEventVarargs(eventId, &childActivityID, args); - } - - #endregion - - #region IDisposable Members - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - /// - /// Disposes of an EventSource. - /// - /// - /// Called from Dispose() with disposing=true, and from the finalizer (~MeasurementBlock) with disposing=false. - /// Guidelines: - /// 1. We may be called more than once: do nothing after the first call. - /// 2. Avoid throwing exceptions if disposing is false, i.e. if we're being finalized. - /// - /// True if called from Dispose(), false if called from the finalizer. - protected virtual void Dispose(bool disposing) - { - if (disposing) - { -#if FEATURE_MANAGED_ETW - if (m_provider != null) - { - m_provider.Dispose(); - m_provider = null; - } -#endif - } - } - ~EventSource() - { - this.Dispose(false); - } - #endregion - - #region private - private static Guid GenerateGuidFromName(string name) - { - // The algorithm below is following the guidance of http://www.ietf.org/rfc/rfc4122.txt - // Create a blob containing a 16 byte number representing the namespace - // followed by the unicode bytes in the name. - var bytes = new byte[name.Length * 2 + 16]; - uint namespace1 = 0x482C2DB2; - uint namespace2 = 0xC39047c8; - uint namespace3 = 0x87F81A15; - uint namespace4 = 0xBFC130FB; - // Write the bytes most-significant byte first. - for (int i = 3; 0 <= i; --i) - { - bytes[i] = (byte)namespace1; - namespace1 >>= 8; - bytes[i + 4] = (byte)namespace2; - namespace2 >>= 8; - bytes[i + 8] = (byte)namespace3; - namespace3 >>= 8; - bytes[i + 12] = (byte)namespace4; - namespace4 >>= 8; - } - // Write out the name, most significant byte first - for (int i = 0; i < name.Length; i++) - { - bytes[2 * i + 16 + 1] = (byte)name[i]; - bytes[2 * i + 16] = (byte)(name[i] >> 8); - } - - // Compute the Sha1 hash - var sha1 = System.Security.Cryptography.SHA1.Create(); - byte[] hash = sha1.ComputeHash(bytes); - - // Create a GUID out of the first 16 bytes of the hash (SHA-1 create a 20 byte hash) - int a = (((((hash[3] << 8) + hash[2]) << 8) + hash[1]) << 8) + hash[0]; - short b = (short)((hash[5] << 8) + hash[4]); - short c = (short)((hash[7] << 8) + hash[6]); - - c = (short)((c & 0x0FFF) | 0x5000); // Set high 4 bits of octet 7 to 5, as per RFC 4122 - Guid guid = new Guid(a, b, c, hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]); - return guid; - } - - [SecurityCritical] - private unsafe object DecodeObject(int eventId, int parameterId, IntPtr dataPointer) - { - Type dataType = m_eventData[eventId].Parameters[parameterId].ParameterType; - - Again: - if (dataType == typeof(IntPtr)) - { - return *((IntPtr*)dataPointer); - } - else if (dataType == typeof(int)) - { - return *((int*)dataPointer); - } - else if (dataType == typeof(uint)) - { - return *((uint*)dataPointer); - } - else if (dataType == typeof(long)) - { - return *((long*)dataPointer); - } - else if (dataType == typeof(ulong)) - { - return *((ulong*)dataPointer); - } - else if (dataType == typeof(byte)) - { - return *((byte*)dataPointer); - } - else if (dataType == typeof(sbyte)) - { - return *((sbyte*)dataPointer); - } - else if (dataType == typeof(short)) - { - return *((short*)dataPointer); - } - else if (dataType == typeof(ushort)) - { - return *((ushort*)dataPointer); - } - else if (dataType == typeof(float)) - { - return *((float*)dataPointer); - } - else if (dataType == typeof(double)) - { - return *((double*)dataPointer); - } - else if (dataType == typeof(decimal)) - { - return *((decimal*)dataPointer); - } - else if (dataType == typeof(bool)) - { - // The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does. - if (*((int*)dataPointer) == 1) - { - return true; - } - else - { - return false; - } - } - else if (dataType == typeof(Guid)) - { - return *((Guid*)dataPointer); - } - else if (dataType == typeof(char)) - { - return *((char*)dataPointer); - } - else if (dataType == typeof(DateTime)) - { - long dateTimeTicks = *((long*)dataPointer); - return DateTime.FromFileTimeUtc(dateTimeTicks); - } - else - { - if (dataType.IsEnum) - { - dataType = Enum.GetUnderlyingType(dataType); - goto Again; - } - - // Everything else is marshaled as a string. - // ETW strings are NULL-terminated, so marshal everything up to the first - // null in the string. - return System.Runtime.InteropServices.Marshal.PtrToStringUni(dataPointer); - } - } - - // Finds the Dispatcher (which holds the filtering state), for a given dispatcher for the current - // eventSource). - private EventDispatcher GetDispatcher(EventListener listener) - { - EventDispatcher dispatcher = m_Dispatchers; - while (dispatcher != null) - { - if (dispatcher.m_Listener == listener) - return dispatcher; - dispatcher = dispatcher.m_Next; - } - return dispatcher; - } - - [SecurityCritical] - private unsafe void WriteEventVarargs(int eventId, Guid* childActivityID, object[] args) - { - if (m_eventSourceEnabled) - { - Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. - if (childActivityID != null) - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); - -#if FEATURE_MANAGED_ETW - if (m_eventData[eventId].EnabledForETW) - { -#if FEATURE_ACTIVITYSAMPLING - // this code should be kept in [....] with WriteEventWithRelatedActivityIdCore(). - SessionMask etwSessions = SessionMask.All; - // only compute etwSessions if there are *any* ETW filters enabled... - if ((ulong)m_curLiveSessions != 0) - etwSessions = GetEtwSessionMask(eventId, childActivityID); - - if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0) - { - if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions)) - { - // by default the Descriptor.Keyword will have the perEventSourceSessionId bit - // mask set to 0x0f so, when all ETW sessions want the event we don't need to - // synthesize a new one - if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, childActivityID, args)) - ThrowEventSourceException(); - } - else - { - long origKwd = (long)((ulong) m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())); - // only some of the ETW sessions will receive this event. Synthesize a new - // Descriptor whose Keywords field will have the appropriate bits set. - var desc = new System.Diagnostics.Tracing.EventDescriptor( - m_eventData[eventId].Descriptor.EventId, - m_eventData[eventId].Descriptor.Version, - m_eventData[eventId].Descriptor.Channel, - m_eventData[eventId].Descriptor.Level, - m_eventData[eventId].Descriptor.Opcode, - m_eventData[eventId].Descriptor.Task, - (long)(ulong)etwSessions | origKwd); - - if (!m_provider.WriteEvent(ref desc, childActivityID, args)) - ThrowEventSourceException(); - } - } -#else - if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, childActivityID, args)) - ThrowEventSourceException(); -#endif // FEATURE_ACTIVITYSAMPLING - } -#endif // FEATURE_MANAGED_ETW - if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener) - WriteToAllListeners(eventId, childActivityID, args); - } - } - - [SecurityCritical] - unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) - { - object[] args = new object[eventDataCount]; - - for (int i = 0; i < eventDataCount; i++) - args[i] = DecodeObject(eventId, i, data[i].DataPointer); - WriteToAllListeners(eventId, childActivityID, args); - } - - // helper for writing to all EventListeners attached the current eventSource. - [SecurityCritical] - unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, params object[] args) - { - EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); - eventCallbackArgs.EventId = eventId; - if (childActivityID != null) - eventCallbackArgs.RelatedActivityId = *childActivityID; - eventCallbackArgs.Payload = new ReadOnlyCollection(new List(args)); - - Exception lastThrownException = null; - for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next) - { - if (dispatcher.m_EventEnabled[eventId]) - { -#if FEATURE_ACTIVITYSAMPLING - var activityFilter = dispatcher.m_Listener.m_activityFilter; - // order below is important as PassesActivityFilter will "flow" active activities - // even when the current EventSource doesn't have filtering enabled. This allows - // interesting activities to be updated so that sources that do sample can get - // accurate data - if (activityFilter == null || - ActivityFilter.PassesActivityFilter(activityFilter, childActivityID, - m_eventData[eventId].TriggersActivityTracking > 0, - this, eventId) || - !dispatcher.m_activityFilteringEnabled) -#endif // FEATURE_ACTIVITYSAMPLING - { - try - { - dispatcher.m_Listener.OnEventWritten(eventCallbackArgs); - } - catch (Exception e) - { - ReportOutOfBandMessage("ERROR: Exception during EventSource.OnEventWritten: " - + e.Message, false); - lastThrownException = e; - } - } - } - } - - if (lastThrownException != null) - { - throw new EventSourceException(lastThrownException); - } - } - - [SecuritySafeCritical] - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - private unsafe void WriteEventString(EventLevel level, long keywords, string msg) - { - if (m_eventSourceEnabled) - { - if (m_provider != null && !m_provider.WriteEventString(level, keywords, msg)) - { - ThrowEventSourceException(); - } - } - } - - private void WriteStringToAllListeners(string msg) - { - EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); - eventCallbackArgs.EventId = 0; - eventCallbackArgs.Message = msg; - - Exception lastThrownException = null; - for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next) - { - // if there's *any* enabled event on the dispatcher we'll write out the string - // otherwise we'll treat the listener as disabled and skip it - bool dispatcherEnabled = false; - for (int evtId = 0; evtId < dispatcher.m_EventEnabled.Length; ++evtId) - { - if (dispatcher.m_EventEnabled[evtId]) - { - dispatcherEnabled = true; - break; - } - } - try - { - if (dispatcherEnabled) - dispatcher.m_Listener.OnEventWritten(eventCallbackArgs); - } - catch (Exception e) - { - lastThrownException = e; - } - } - if (lastThrownException != null) - { - throw new EventSourceException(lastThrownException); - } - } - -#if FEATURE_ACTIVITYSAMPLING - [SecurityCritical] - unsafe private SessionMask GetEtwSessionMask(int eventId, Guid* childActivityID) - { - SessionMask etwSessions = new SessionMask(); - - for (int i = 0; i < SessionMask.MAX; ++i) - { - EtwSession etwSession = m_etwSessionIdMap[i]; - if (etwSession != null) - { - ActivityFilter activityFilter = etwSession.m_activityFilter; - // PassesActivityFilter() will flow "interesting" activities, so make sure - // to perform this test first, before ORing with ~m_activityFilteringForETWEnabled - // (note: the first test for !m_activityFilteringForETWEnabled[i] ensures we - // do not fire events indiscriminately, when no filters are specified, but only - // if, in addition, the session did not also enable ActivitySampling) - if (activityFilter == null && !m_activityFilteringForETWEnabled[i] || - activityFilter != null && - ActivityFilter.PassesActivityFilter(activityFilter, childActivityID, - m_eventData[eventId].TriggersActivityTracking > 0, this, eventId) || - !m_activityFilteringForETWEnabled[i]) - { - etwSessions[i] = true; - } - } - } - // flow "interesting" activities for all legacy sessions in which there's some - // level of activity tracing enabled (even other EventSources) - if (m_legacySessions != null && m_legacySessions.Count > 0 && - (EventOpcode)m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send) - { - // only calculate InternalCurrentThreadActivityId once - Guid *pCurrentActivityId = null; - Guid currentActivityId; - foreach (var legacyEtwSession in m_legacySessions) - { - if (legacyEtwSession == null) - continue; - - ActivityFilter activityFilter = legacyEtwSession.m_activityFilter; - if (activityFilter != null) - { - if (pCurrentActivityId == null) - { - currentActivityId = InternalCurrentThreadActivityId; - pCurrentActivityId = ¤tActivityId; - } - ActivityFilter.FlowActivityIfNeeded(activityFilter, pCurrentActivityId, childActivityID); - } - } - } - - return etwSessions; - } -#endif // FEATURE_ACTIVITYSAMPLING - - /// - /// Returns true if 'eventNum' is enabled if you only consider the level and matchAnyKeyword filters. - /// It is possible that eventSources turn off the event based on additional filtering criteria. - /// - private bool IsEnabledByDefault(int eventNum, bool enable, EventLevel currentLevel, EventKeywords currentMatchAnyKeyword) - { - if (!enable) - return false; - - EventLevel eventLevel = (EventLevel)m_eventData[eventNum].Descriptor.Level; - EventKeywords eventKeywords = (EventKeywords)((ulong)m_eventData[eventNum].Descriptor.Keywords & (~(SessionMask.All.ToEventKeywords()))); - - if ((eventLevel <= currentLevel) || (currentLevel == 0)) - { - if ((eventKeywords == 0) || ((eventKeywords & currentMatchAnyKeyword) != 0)) - return true; - } - return false; - } - - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] - private void ThrowEventSourceException() - { - // Only throw an error if we asked for them. - if (m_throwOnEventWriteErrors) - { - // - switch (EventProvider.GetLastWriteEventError()) - { - case EventProvider.WriteEventErrorCode.EventTooBig: - ReportOutOfBandMessage("EventSourceException: "+Environment.GetResourceString("EventSource_EventTooBig"), true); - throw new EventSourceException(Environment.GetResourceString("EventSource_EventTooBig")); - case EventProvider.WriteEventErrorCode.NoFreeBuffers: - ReportOutOfBandMessage("EventSourceException: "+Environment.GetResourceString("EventSource_NoFreeBuffers"), true); - throw new EventSourceException(Environment.GetResourceString("EventSource_NoFreeBuffers")); - case EventProvider.WriteEventErrorCode.NullInput: - ReportOutOfBandMessage("EventSourceException: "+Environment.GetResourceString("EventSource_NullInput"), true); - throw new EventSourceException(Environment.GetResourceString("EventSource_NullInput")); - case EventProvider.WriteEventErrorCode.TooManyArgs: - ReportOutOfBandMessage("EventSourceException: "+Environment.GetResourceString("EventSource_TooManyArgs"), true); - throw new EventSourceException(Environment.GetResourceString("EventSource_TooManyArgs")); - default: - ReportOutOfBandMessage("EventSourceException", true); - throw new EventSourceException(); - } - } - } - - private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData) - { - if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send && - (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive) - { - ThrowEventSourceException(); - } - } - -#if FEATURE_MANAGED_ETW - /// - /// This class lets us hook the 'OnEventCommand' from the eventSource. - /// - private class OverideEventProvider : EventProvider - { - public OverideEventProvider(EventSource eventSource) - { - this.m_eventSource = eventSource; - } - protected override void OnControllerCommand(ControllerCommand command, IDictionary arguments, - int perEventSourceSessionId, int etwSessionId) - { - // We use null to represent the ETW EventListener. - EventListener listener = null; - m_eventSource.SendCommand(listener, perEventSourceSessionId, etwSessionId, - (EventCommand)command, IsEnabled(), Level, MatchAnyKeyword, arguments); - } - private EventSource m_eventSource; - } -#endif - - /// - /// Used to hold all the static information about an event. This includes everything in the event - /// descriptor as well as some stuff we added specifically for EventSource. see the - /// code:m_eventData for where we use this. - /// - internal struct EventMetadata - { - public System.Diagnostics.Tracing.EventDescriptor Descriptor; - public bool EnabledForAnyListener; // true if any dispatcher has this event turned on - public bool EnabledForETW; // is this event on for the OS ETW data dispatcher? - public byte TriggersActivityTracking; // count of listeners that marked this event as trigger for start of activity logging. - public string Name; // the name of the event - public string Message; // If the event has a message associated with it, this is it. - public ParameterInfo[] Parameters; // - }; - - // This is the internal entry point that code:EventListeners call when wanting to send a command to a - // eventSource. The logic is as follows - // - // * if Command == Update - // * perEventSourceSessionId specifies the per-provider ETW session ID that the command applies - // to (if listener != null) - // perEventSourceSessionId = 0 - reserved for EventListeners - // perEventSourceSessionId = 1..SessionMask.MAX - reserved for activity tracing aware ETW sessions - // perEventSourceSessionId-1 represents the bit in the reserved field (bits 44..47) in - // Keywords that identifies the session - // perEventSourceSessionId = SessionMask.MAX+1 - reserved for legacy ETW sessions; these are - // discriminated by etwSessionId - // * etwSessionId specifies a machine-wide ETW session ID; this allows correlation of - // activity tracing across different providers (which might have different sessionIds - // for the same ETW session) - // * enable, level, matchAnyKeywords are used to set a default for all events for the - // eventSource. In particular, if 'enabled' is false, 'level' and - // 'matchAnyKeywords' are not used. - // * OnEventCommand is invoked, which may cause calls to - // code:EventSource.EnableEventForDispatcher which may cause changes in the filtering - // depending on the logic in that routine. - // * else (command != Update) - // * Simply call OnEventCommand. The expectation is that filtering is NOT changed. - // * The 'enabled' 'level', matchAnyKeyword' arguments are ignored (must be true, 0, 0). - // - // dispatcher == null has special meaning. It is the 'ETW' dispatcher. - internal void SendCommand(EventListener listener, int perEventSourceSessionId, int etwSessionId, - EventCommand command, bool enable, - EventLevel level, EventKeywords matchAnyKeyword, - IDictionary commandArguments) - { - m_lastCommandException = null; - bool shouldReport = (perEventSourceSessionId > 0) && (perEventSourceSessionId <= SessionMask.MAX); - - try - { - lock (EventListener.EventListenersLock) - { - EnsureInitialized(); - - // Find the per-EventSource dispatcher cooresponding to registered dispatcher - EventDispatcher eventSourceDispatcher = GetDispatcher(listener); - if (eventSourceDispatcher == null && listener != null) // dispatcher == null means ETW dispatcher - throw new ArgumentException(Environment.GetResourceString("EventSource_ListenerNotFound")); - - if (commandArguments == null) - commandArguments = new Dictionary(); - - if (command == EventCommand.Update) - { - // Set it up using the 'standard' filtering bitfields (use the "global" enable, not session specific one) - for (int i = 0; i < m_eventData.Length; i++) - EnableEventForDispatcher(eventSourceDispatcher, i, IsEnabledByDefault(i, enable, level, matchAnyKeyword)); - - if (enable) - { - if (!m_eventSourceEnabled) - { - // EventSource turned on for the first time, simply copy the bits. - m_level = level; - m_matchAnyKeyword = matchAnyKeyword; - } - else - { - // Already enabled, make it the most verbose of the existing and new filter - if (level > m_level) - m_level = level; - if (matchAnyKeyword == 0) - m_matchAnyKeyword = 0; - else if (m_matchAnyKeyword != 0) - m_matchAnyKeyword |= matchAnyKeyword; - } - } - - // interpret perEventSourceSessionId's sign, and adjust perEventSourceSessionId to - // represent 0-based positive values - bool bSessionEnable = (perEventSourceSessionId >= 0); - if (perEventSourceSessionId == 0 && enable == false) - bSessionEnable = false; - - if (listener == null) - { - if (!bSessionEnable) - perEventSourceSessionId = -perEventSourceSessionId; - // for "global" enable/disable (passed in with listener == null and - // perEventSourceSessionId == 0) perEventSourceSessionId becomes -1 - --perEventSourceSessionId; - } - - command = bSessionEnable ? EventCommand.Enable : EventCommand.Disable; - - // perEventSourceSessionId = -1 when ETW sent a notification, but the set of active sessions - // hasn't changed. - // sesisonId = SessionMask.MAX when one of the legacy ETW sessions changed - // 0 <= perEventSourceSessionId < SessionMask.MAX for activity-tracing aware sessions - Contract.Assert(perEventSourceSessionId >= -1 && perEventSourceSessionId <= SessionMask.MAX); - - // Send the manifest if we are enabling an ETW session - if (bSessionEnable && eventSourceDispatcher == null) - { - // eventSourceDispatcher == null means this is the ETW manifest - - // SendCommand can be called from the EventSource constructor as a side effect of - // ETW registration. Unfortunately when this callback is active the provider is - // not actually enabled (WriteEvents will fail). Thus if we detect this condition - // (that we are still being constructed), we simply skip sending the manifest. - // When the constructor completes we will try again and send the manifest at that time. - // - // Note that we unconditionally send the manifest whenever we are enabled, even if - // we were already enabled. This is because there may be multiple sessions active - // and we can't know that all the sessions have seen the manifest. - if (m_completelyInited) - SendManifest(m_rawManifest); - else - m_deferedSendManifest = true; - } - -#if FEATURE_ACTIVITYSAMPLING - if (bSessionEnable && perEventSourceSessionId != -1) - { - bool participateInSampling = false; - string activityFilters; - int sessionIdBit; - - ParseCommandArgs(commandArguments, out participateInSampling, - out activityFilters, out sessionIdBit); - - if (listener == null && commandArguments.Count > 0 && perEventSourceSessionId != sessionIdBit) - { - throw new ArgumentException(Environment.GetResourceString("EventSource_SessionIdError", - perEventSourceSessionId+SessionMask.SHIFT_SESSION_TO_KEYWORD, - sessionIdBit+SessionMask.SHIFT_SESSION_TO_KEYWORD)); - } - - if (listener == null) - { - UpdateEtwSession(perEventSourceSessionId, etwSessionId, true, activityFilters, participateInSampling); - } - else - { - ActivityFilter.UpdateFilter(ref listener.m_activityFilter, this, 0, activityFilters); - eventSourceDispatcher.m_activityFilteringEnabled = participateInSampling; - } - } - else if (!bSessionEnable && listener == null) - { - // if we disable an ETW session, indicate that in a synthesized command argument - if (perEventSourceSessionId >= 0 && perEventSourceSessionId < SessionMask.MAX) - { - commandArguments["EtwSessionKeyword"] = (perEventSourceSessionId+SessionMask.SHIFT_SESSION_TO_KEYWORD).ToString(CultureInfo.InvariantCulture); - } - } -#endif // FEATURE_ACTIVITYSAMPLING - - this.OnEventCommand(new EventCommandEventArgs(command, commandArguments, this, eventSourceDispatcher)); - -#if FEATURE_ACTIVITYSAMPLING - if (listener == null && !bSessionEnable && perEventSourceSessionId != -1) - { - // if we disable an ETW session, complete disabling it - UpdateEtwSession(perEventSourceSessionId, etwSessionId, false, null, false); - } -#endif // FEATURE_ACTIVITYSAMPLING - - if (enable) - { - m_eventSourceEnabled = true; - } - else - { - // If we are disabling, maybe we can turn on 'quick checks' to filter - // quickly. These are all just optimizations (since later checks will still filter) - -#if FEATURE_ACTIVITYSAMPLING - // Turn off (and forget) any information about Activity Tracing. - if (listener == null) - { - // reset all filtering information for activity-tracing-aware sessions - for (int i = 0; i < SessionMask.MAX; ++i) - { - EtwSession etwSession = m_etwSessionIdMap[i]; - if (etwSession != null) - ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this); - } - m_activityFilteringForETWEnabled = new SessionMask(0); - m_curLiveSessions = new SessionMask(0); - // reset activity-tracing-aware sessions - if (m_etwSessionIdMap != null) - for (int i = 0; i < SessionMask.MAX; ++i) - m_etwSessionIdMap[i] = null; - // reset legacy sessions - if (m_legacySessions != null) - m_legacySessions.Clear(); - } - else - { - ActivityFilter.DisableFilter(ref listener.m_activityFilter, this); - eventSourceDispatcher.m_activityFilteringEnabled = false; - } -#endif // FEATURE_ACTIVITYSAMPLING - - // There is a good chance EnabledForAnyListener are not as accurate as - // they could be, go ahead and get a better estimate. - for (int i = 0; i < m_eventData.Length; i++) - { - bool isEnabledForAnyListener = false; - for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next) - { - if (dispatcher.m_EventEnabled[i]) - { - isEnabledForAnyListener = true; - break; - } - } - m_eventData[i].EnabledForAnyListener = isEnabledForAnyListener; - } - - // If no events are enabled, disable the global enabled bit. - if (!AnyEventEnabled()) - { - m_level = 0; - m_matchAnyKeyword = 0; - m_eventSourceEnabled = false; - } - } -#if FEATURE_ACTIVITYSAMPLING - UpdateKwdTriggers(enable); -#endif // FEATURE_ACTIVITYSAMPLING - } - else - { - if (command == EventCommand.SendManifest) - SendManifest(m_rawManifest); - - // These are not used for non-update commands and thus should always be 'default' values - Contract.Assert(enable == true); - Contract.Assert(m_level == EventLevel.LogAlways); - Contract.Assert(m_matchAnyKeyword == EventKeywords.None); - - this.OnEventCommand(new EventCommandEventArgs(command, commandArguments, null, null)); - } - -#if FEATURE_ACTIVITYSAMPLING - if (m_completelyInited && (listener != null || shouldReport)) - { - SessionMask m = SessionMask.FromId(perEventSourceSessionId); - ReportActivitySamplingInfo(listener, m); - } - OutputDebugString(string.Format(CultureInfo.InvariantCulture, "{0}.SendCommand(session {1}, cmd {2}, enable {3}, level {4}): live sessions {5:x}, sampling {6:x}", - m_name, perEventSourceSessionId, command, enable, level, - (ulong) m_curLiveSessions, (ulong) m_activityFilteringForETWEnabled)); -#endif // FEATURE_ACTIVITYSAMPLING - } - } - catch (Exception e) - { - // Remember any exception and rethrow. - m_lastCommandException = e; - throw; - } - } - -#if FEATURE_ACTIVITYSAMPLING - - internal void UpdateEtwSession( - int sessionIdBit, - int etwSessionId, - bool bEnable, - string activityFilters, - bool participateInSampling) - { - if (sessionIdBit < SessionMask.MAX) - { - // activity-tracing-aware etw session - if (bEnable) - { - var etwSession = EtwSession.GetEtwSession(etwSessionId, true); - ActivityFilter.UpdateFilter(ref etwSession.m_activityFilter, this, sessionIdBit, activityFilters); - m_etwSessionIdMap[sessionIdBit] = etwSession; - m_activityFilteringForETWEnabled[sessionIdBit] = participateInSampling; - } - else - { - var etwSession = EtwSession.GetEtwSession(etwSessionId); - ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this); - m_etwSessionIdMap[sessionIdBit] = null; - m_activityFilteringForETWEnabled[sessionIdBit] = false; - // the ETW session is going away; remove it from the global list - EtwSession.RemoveEtwSession(etwSession); - } - m_curLiveSessions[sessionIdBit] = bEnable; - } - else - { - // legacy etw session - if (bEnable) - { - if (m_legacySessions == null) - m_legacySessions = new List(8); - var etwSession = EtwSession.GetEtwSession(etwSessionId, true); - if (!m_legacySessions.Contains(etwSession)) - m_legacySessions.Add(etwSession); - } - else - { - var etwSession = EtwSession.GetEtwSession(etwSessionId); - if (m_legacySessions != null) - m_legacySessions.Remove(etwSession); - // the ETW session is going away; remove it from the global list - EtwSession.RemoveEtwSession(etwSession); - } - } - } - - internal static bool ParseCommandArgs( - IDictionary commandArguments, - out bool participateInSampling, - out string activityFilters, - out int sessionIdBit) - { - bool res = true; - participateInSampling = false; - string activityFilterString; - if (commandArguments.TryGetValue("ActivitySamplingStartEvent", out activityFilters)) - { - // if a start event is specified default the event source to participate in sampling - participateInSampling = true; - } - - if (commandArguments.TryGetValue("ActivitySampling", out activityFilterString)) - { - if (string.Compare(activityFilterString, "false", StringComparison.OrdinalIgnoreCase) == 0 || - activityFilterString == "0") - participateInSampling = false; - else - participateInSampling = true; - } - - string sSessionKwd; - int sessionKwd = -1; - if (!commandArguments.TryGetValue("EtwSessionKeyword", out sSessionKwd) || - !int.TryParse(sSessionKwd, out sessionKwd) || - sessionKwd < SessionMask.SHIFT_SESSION_TO_KEYWORD || - sessionKwd >= SessionMask.SHIFT_SESSION_TO_KEYWORD + SessionMask.MAX) - { - sessionIdBit = -1; - res = false; - } - else - { - sessionIdBit = sessionKwd - SessionMask.SHIFT_SESSION_TO_KEYWORD; - } - return res; - } - - internal void UpdateKwdTriggers(bool enable) - { - if (enable) - { - // recompute m_keywordTriggers - ulong gKeywords = (ulong)m_matchAnyKeyword; - if (gKeywords == 0) - gKeywords = 0xFFFFffffFFFFffff; - - m_keywordTriggers = 0; - for (int sessId = 0; sessId < SessionMask.MAX; ++sessId) - { - EtwSession etwSession = m_etwSessionIdMap[sessId]; - if (etwSession == null) - continue; - - ActivityFilter activityFilter = etwSession.m_activityFilter; - ActivityFilter.UpdateKwdTriggers(activityFilter, m_guid, this, (EventKeywords)gKeywords); - } - } - else - { - m_keywordTriggers = 0; - } - } - -#endif // FEATURE_ACTIVITYSAMPLING - - /// - /// If 'value is 'true' then set the eventSource so that 'dispatcher' will recieve event with the eventId - /// of 'eventId. If value is 'false' disable the event for that dispatcher. If 'eventId' is out of - /// range return false, otherwise true. - /// - internal bool EnableEventForDispatcher(EventDispatcher dispatcher, int eventId, bool value) - { - if (dispatcher == null) - { - if (eventId >= m_eventData.Length) - return false; -#if FEATURE_MANAGED_ETW - if (m_provider != null) - m_eventData[eventId].EnabledForETW = value; -#endif - } - else - { - if (eventId >= dispatcher.m_EventEnabled.Length) - return false; - dispatcher.m_EventEnabled[eventId] = value; - if (value) - m_eventData[eventId].EnabledForAnyListener = true; - } - return true; - } - - /// - /// Returns true if any event at all is on. - /// - private bool AnyEventEnabled() - { - for (int i = 0; i < m_eventData.Length; i++) - if (m_eventData[i].EnabledForETW || m_eventData[i].EnabledForAnyListener) - return true; - return false; - } - - [SecuritySafeCritical] - private void EnsureInitialized() - { - Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); - if (m_rawManifest == null) - { - Contract.Assert(m_rawManifest == null); - m_rawManifest = CreateManifestAndDescriptors(this.GetType(), Name, this); - - // - foreach (WeakReference eventSourceRef in EventListener.s_EventSources) - { - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource != null && eventSource.Guid == m_guid) - { - if (eventSource != this) - throw new ArgumentException(Environment.GetResourceString("EventSource_EventSourceGuidInUse", m_guid)); - } - } - - // Make certain all dispatchers are also have their array's initialized - EventDispatcher dispatcher = m_Dispatchers; - while (dispatcher != null) - { - if (dispatcher.m_EventEnabled == null) - dispatcher.m_EventEnabled = new bool[m_eventData.Length]; - dispatcher = dispatcher.m_Next; - } - } - if (s_currentPid == 0) - { - s_currentPid = Win32Native.GetCurrentProcessId(); - } - } - - // Send out the ETW manifest XML out to ETW - // Today, we only send the manifest to ETW, custom listeners don't get it. - [SecuritySafeCritical] - private unsafe bool SendManifest(byte[] rawManifest) - { - bool success = true; - -#if FEATURE_MANAGED_ETW - fixed (byte* dataPtr = rawManifest) - { - var manifestDescr = new System.Diagnostics.Tracing.EventDescriptor(0xFFFE, 1, 0, 0, 0xFE, 0xFFFE, -1); - ManifestEnvelope envelope = new ManifestEnvelope(); - - envelope.Format = ManifestEnvelope.ManifestFormats.SimpleXmlFormat; - envelope.MajorVersion = 1; - envelope.MinorVersion = 0; - envelope.Magic = 0x5B; // An unusual number that can be checked for consistancy. - int dataLeft = rawManifest.Length; - envelope.TotalChunks = (ushort)((dataLeft + (ManifestEnvelope.MaxChunkSize - 1)) / ManifestEnvelope.MaxChunkSize); - envelope.ChunkNumber = 0; - - EventProvider.EventData* dataDescrs = stackalloc EventProvider.EventData[2]; - dataDescrs[0].Ptr = (ulong)&envelope; - dataDescrs[0].Size = (uint)sizeof(ManifestEnvelope); - dataDescrs[0].Reserved = 0; - - dataDescrs[1].Ptr = (ulong)dataPtr; - dataDescrs[1].Reserved = 0; - - int chunkSize = ManifestEnvelope.MaxChunkSize; - TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE: - - while (dataLeft > 0) - { - dataDescrs[1].Size = (uint)Math.Min(dataLeft, chunkSize); - if (m_provider != null) - { - if (!m_provider.WriteEvent(ref manifestDescr, null, 2, (IntPtr)dataDescrs)) - { - // Turns out that if users set the BufferSize to something less than 64K then WriteEvent - // can fail. If we get this failure on the first chunk try again with something smaller - // The smallest BufferSize is 1K so if we get to 512, we can give up making it smaller. - if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig) - { - chunkSize = chunkSize / 2; - if (envelope.ChunkNumber == 0 && chunkSize > 512) - goto TRY_AGAIN_WITH_SMALLER_CHUNK_SIZE; - } - success = false; - if(m_throwOnEventWriteErrors) - ThrowEventSourceException(); - } - } - dataLeft -= ManifestEnvelope.MaxChunkSize; - dataDescrs[1].Ptr += ManifestEnvelope.MaxChunkSize; - envelope.ChunkNumber++; - } - } -#endif - - return success; - } - - - // Helper to deal with the fact that the type we are reflecting over might be loaded in the ReflectionOnly context. - // When that is the case, we have the build the custom assemblies on a member by hand. - internal static Attribute GetCustomAttributeHelper(MemberInfo member, Type attributeType) - { - if (!member.Module.Assembly.ReflectionOnly) - { - // Let the runtime to the work for us, since we can execute code in this context. - return Attribute.GetCustomAttribute(member, attributeType, false); - } - - // In the reflection only context, we have to do things by hand. - string fullTypeNameToFind = attributeType.FullName; - -#if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT - fullTypeNameToFind = fullTypeNameToFind.Replace("System.Diagnostics.Eventing", "System.Diagnostics.Tracing"); -#endif - - foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(member)) - { - string attributeFullTypeName = data.Constructor.ReflectedType.FullName; -#if EVENT_SOURCE_LEGACY_NAMESPACE_SUPPORT - attributeFullTypeName = attributeFullTypeName.Replace("System.Diagnostics.Eventing", "System.Diagnostics.Tracing"); -#endif - - if (String.Equals(attributeFullTypeName, fullTypeNameToFind, StringComparison.Ordinal)) - { - Attribute attr = null; - - Contract.Assert(data.ConstructorArguments.Count <= 1); - - if (data.ConstructorArguments.Count == 1) - { - attr = (Attribute)Activator.CreateInstance(attributeType, new object[] { data.ConstructorArguments[0].Value }); - } - else if (data.ConstructorArguments.Count == 0) - { - attr = (Attribute)Activator.CreateInstance(attributeType); - } - - if (attr != null) - { - Type t = attr.GetType(); - - foreach (CustomAttributeNamedArgument namedArgument in data.NamedArguments) - { - PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance); - object value = namedArgument.TypedValue.Value; - - if (p.PropertyType.IsEnum) - { - value = Enum.Parse(p.PropertyType, value.ToString()); - } - - p.SetValue(attr, value, null); - } - - return attr; - } - } - } - - return null; - } - - // Use reflection to look at the attributes of a class, and generate a manifest for it (as UTF8) and - // return the UTF8 bytes. It also sets up the code:EventData structures needed to dispatch events - // at run time. 'source' is the event source to place the descriptors. If it is null, - // then the descriptors are not creaed, and just the manifest is generated. - private static byte[] CreateManifestAndDescriptors(Type eventSourceType, string eventSourceDllName, EventSource source) - { - MethodInfo[] methods = eventSourceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - EventAttribute defaultEventAttribute; - int eventId = 1; // The number given to an event that does not have a explicitly given ID. - EventMetadata[] eventData = null; - Dictionary eventsByName = null; - if (source != null) - eventData = new EventMetadata[methods.Length]; - - // See if we have localization information. - ResourceManager resources = null; - EventSourceAttribute eventSourceAttrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute)); - if (eventSourceAttrib != null && eventSourceAttrib.LocalizationResources != null) - resources = new ResourceManager(eventSourceAttrib.LocalizationResources, eventSourceType.Assembly); - - ManifestBuilder manifest = new ManifestBuilder(GetName(eventSourceType), GetGuid(eventSourceType), eventSourceDllName, resources); - - // Collect task, opcode, keyword and channel information -#if FEATURE_MANAGED_ETW_CHANNELS - foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes", "Channels" }) -#else - foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes" }) -#endif - { - Type nestedType = eventSourceType.GetNestedType(providerEnumKind); - if (nestedType != null) - { - foreach (FieldInfo staticField in nestedType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) - { - AddProviderEnumKind(manifest, staticField, providerEnumKind); - } - } - } - - for (int i = 0; i < methods.Length; i++) - { - MethodInfo method = methods[i]; - ParameterInfo[] args = method.GetParameters(); - - // Get the EventDescriptor (from the Custom attributes) - EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute)); - - // Methods that don't return void can't be events. - if (method.ReturnType != typeof(void)) - { - if (eventAttribute != null) - throw new ArgumentException(Environment.GetResourceString("EventSource_AttributeOnNonVoid", method.Name)); - continue; - } - if (method.IsVirtual || method.IsStatic) - { - continue; - } - - if (eventAttribute == null) - { - // If we explictly mark the method as not being an event, then honor that. - if (GetCustomAttributeHelper(method, typeof(NonEventAttribute)) != null) - continue; - - defaultEventAttribute = new EventAttribute(eventId); - eventAttribute = defaultEventAttribute; - } - else if (eventAttribute.EventId <= 0) - throw new ArgumentException(Environment.GetResourceString("EventSource_NeedPositiveId")); - else if ((ulong)eventAttribute.Keywords >= 0x0000100000000000UL) - throw new ArgumentException(Environment.GetResourceString("EventSource_ReservedKeywords")); - eventId++; - - // Auto-assign tasks, starting with the highest task number and working back - if (eventAttribute.Opcode == EventOpcode.Info && eventAttribute.Task == EventTask.None) - eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId); - - manifest.StartEvent(method.Name, eventAttribute); - for (int fieldIdx = 0; fieldIdx < args.Length; fieldIdx++) - { - // If the first parameter is 'RelatedActivityId' then skip it. - if (fieldIdx == 0 && args[fieldIdx].ParameterType == typeof(Guid) && - string.Compare(args[fieldIdx].Name, "RelatedActivityId", StringComparison.OrdinalIgnoreCase) == 0) - continue; - manifest.AddEventParameter(args[fieldIdx].ParameterType, args[fieldIdx].Name); - } - manifest.EndEvent(); - - if (source != null) - { - // Do checking for user errors (optional, but nto a big deal so we do it). - DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute); - AddEventDescriptor(ref eventData, method.Name, eventAttribute, args); - } - } - - if (source != null) - { - TrimEventDescriptors(ref eventData); - source.m_eventData = eventData; // officaly initialize it. We do this at most once (it is racy otherwise). - } - - return manifest.CreateManifest(); - } - - // adds a enumeration (keyword, opcode, task or channel) represented by 'staticField' - // to the manifest. - private static void AddProviderEnumKind(ManifestBuilder manifest, FieldInfo staticField, string providerEnumKind) - { - Type staticFieldType = staticField.FieldType; - if (staticFieldType == typeof(EventOpcode)) - { - if (providerEnumKind != "Opcodes") goto Error; - int value = (int)staticField.GetRawConstantValue(); - if (value <= 10) - throw new ArgumentException(Environment.GetResourceString("EventSource_ReservedOpcode")); - manifest.AddOpcode(staticField.Name, value); - } - else if (staticFieldType == typeof(EventTask)) - { - if (providerEnumKind != "Tasks") goto Error; - manifest.AddTask(staticField.Name, (int)staticField.GetRawConstantValue()); - } - else if (staticFieldType == typeof(EventKeywords)) - { - if (providerEnumKind != "Keywords") goto Error; - manifest.AddKeyword(staticField.Name, (ulong)(long)staticField.GetRawConstantValue()); - } -#if FEATURE_MANAGED_ETW_CHANNELS - else if (staticFieldType == typeof(EventChannel)) - { - if (providerEnumKind != "Channels") goto Error; - var channelAttribute = (ChannelAttribute)GetCustomAttributeHelper(staticField, typeof(ChannelAttribute)); - manifest.AddChannel(staticField.Name, (byte)staticField.GetRawConstantValue(), channelAttribute); - } -#endif - return; - Error: - throw new ArgumentException(Environment.GetResourceString("EventSource_EnumKindMismatch", staticField.FieldType.Name, providerEnumKind)); - } - - // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method - // with the code:EventAttribute 'eventAttribute'. resourceManger may be null in which case we populate it - // it is populated if we need to look up message resources - private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName, - EventAttribute eventAttribute, ParameterInfo[] eventParameters) - { - if (eventData == null || eventData.Length <= eventAttribute.EventId) - { - EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)]; - Array.Copy(eventData, newValues, eventData.Length); - eventData = newValues; - } - - eventData[eventAttribute.EventId].Descriptor = new System.Diagnostics.Tracing.EventDescriptor( - eventAttribute.EventId, - eventAttribute.Version, -#if FEATURE_MANAGED_ETW_CHANNELS - (byte)eventAttribute.Channel, -#else - (byte)0, -#endif - (byte)eventAttribute.Level, - (byte)eventAttribute.Opcode, - (int)eventAttribute.Task, - (long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords())); - - eventData[eventAttribute.EventId].Name = eventName; - eventData[eventAttribute.EventId].Parameters = eventParameters; - eventData[eventAttribute.EventId].Message = eventAttribute.Message; - } - - // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct - // size after all event descriptors have been added. - private static void TrimEventDescriptors(ref EventMetadata[] eventData) - { - int idx = eventData.Length; - while (0 < idx) - { - --idx; - if (eventData[idx].Descriptor.EventId != 0) - break; - } - if (eventData.Length - idx > 2) // allow one wasted slot. - { - EventMetadata[] newValues = new EventMetadata[idx + 1]; - Array.Copy(eventData, newValues, newValues.Length); - eventData = newValues; - } - } - - // Helper used by code:EventListener.AddEventSource and code:EventListener.EventListener - // when a listener gets attached to a eventSource - internal void AddListener(EventListener listener) - { - lock (EventListener.EventListenersLock) - { - bool[] enabledArray = null; - if (m_eventData != null) - enabledArray = new bool[m_eventData.Length]; - m_Dispatchers = new EventDispatcher(m_Dispatchers, enabledArray, listener); - listener.OnEventSourceCreated(this); - } - } - - // Helper used by code:CreateManifestAndDescriptors to find user mistakes like reusing an event - // index for two distinct events etc. Throws exceptions when it finds something wrong. - private static void DebugCheckEvent(ref Dictionary eventsByName, - EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute) - { - int eventArg = GetHelperCallFirstArg(method); - if (eventArg >= 0 && eventAttribute.EventId != eventArg) - { - throw new ArgumentException(Environment.GetResourceString("EventSource_MismatchIdToWriteEvent", method.Name, eventAttribute.EventId, eventArg)); - } - - if (eventAttribute.EventId < eventData.Length && eventData[eventAttribute.EventId].Descriptor.EventId != 0) - { - throw new ArgumentException(Environment.GetResourceString("EventSource_EventIdReused", method.Name, eventAttribute.EventId)); - } - - if (eventsByName == null) - eventsByName = new Dictionary(); - - if (eventsByName.ContainsKey(method.Name)) - throw new ArgumentException(Environment.GetResourceString("EventSource_EventNameReused", method.Name)); - - eventsByName[method.Name] = method.Name; - } - - /// - /// This method looks at the IL and tries to pattern match against the standard - /// 'boilerplate' event body - /// - /// { if (Enabled()) WriteEvent(#, ...) } - /// - /// If the pattern matches, it returns the literal number passed as the first parameter to - /// the WriteEvent. This is used to find common user errors (mismatching this - /// number with the EventAttribute ID). It is only used for validation. - /// - /// The method to probe. - /// The literal value or -1 if the value could not be determined. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Switch statement is clearer than alternatives")] - [SecuritySafeCritical] - static private int GetHelperCallFirstArg(MethodInfo method) - { - // we need this permission in low trust - new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert(); - // Currently searches for the following pattern - // - // ... // CAN ONLY BE THE INSTRUCTIONS BELOW - // LDARG0 - // LDC.I4 XXX - // ... // CAN ONLY BE THE INSTRUCTIONS BELOW CAN'T BE A BRANCH OR A CALL - // CALL - // NOP // 0 or more times - // RET - // - // If we find this pattern we return the XXX. Otherwise we return -1. - byte[] instrs = method.GetMethodBody().GetILAsByteArray(); - int retVal = -1; - for (int idx = 0; idx < instrs.Length; ) - { - switch (instrs[idx]) - { - case 0: // NOP - case 1: // BREAK - case 2: // LDARG_0 - case 3: // LDARG_1 - case 4: // LDARG_2 - case 5: // LDARG_3 - case 6: // LDLOC_0 - case 7: // LDLOC_1 - case 8: // LDLOC_2 - case 9: // LDLOC_3 - case 10: // STLOC_0 - case 11: // STLOC_1 - case 12: // STLOC_2 - case 13: // STLOC_3 - break; - case 14: // LDARG_S - case 16: // STARG_S - idx++; - break; - case 20: // LDNULL - break; - case 21: // LDC_I4_M1 - case 22: // LDC_I4_0 - case 23: // LDC_I4_1 - case 24: // LDC_I4_2 - case 25: // LDC_I4_3 - case 26: // LDC_I4_4 - case 27: // LDC_I4_5 - case 28: // LDC_I4_6 - case 29: // LDC_I4_7 - case 30: // LDC_I4_8 - if (idx > 0 && instrs[idx - 1] == 2) // preceeded by LDARG0 - retVal = instrs[idx] - 22; - break; - case 31: // LDC_I4_S - if (idx > 0 && instrs[idx - 1] == 2) // preceeded by LDARG0 - retVal = instrs[idx + 1]; - idx++; - break; - case 32: // LDC_I4 - idx += 4; - break; - case 37: // DUP - break; - case 40: // CALL - idx += 4; - - if (retVal >= 0) - { - // Is this call just before return? - for (int search = idx + 1; search < instrs.Length; search++) - { - if (instrs[search] == 42) // RET - return retVal; - if (instrs[search] != 0) // NOP - break; - } - } - retVal = -1; - break; - case 44: // BRFALSE_S - case 45: // BRTRUE_S - retVal = -1; - idx++; - break; - case 57: // BRFALSE - case 58: // BRTRUE - retVal = -1; - idx += 4; - break; - case 103: // CONV_I1 - case 104: // CONV_I2 - case 105: // CONV_I4 - case 106: // CONV_I8 - case 109: // CONV_U4 - case 110: // CONV_U8 - break; - case 140: // BOX - case 141: // NEWARR - idx += 4; - break; - case 162: // STELEM_REF - break; - case 254: // PREFIX - idx++; - // Covers the CEQ instructions used in debug code for some reason. - if (idx >= instrs.Length || instrs[idx] >= 6) - goto default; - break; - default: - /* Contract.Assert(false, "Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] + - " at " + idx + " in method " + method.Name); */ - return -1; - } - idx++; - } - return -1; - } - - [Conditional("DEBUG")] - internal static void OutputDebugString(string msg) - { - msg = msg.TrimEnd('\r', '\n') + - string.Format(CultureInfo.InvariantCulture, ", Thrd({0})"+Environment.NewLine, Thread.CurrentThread.ManagedThreadId); - System.Diagnostics.Debugger.Log(0, null, msg); - } - - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "This does not need to be correct when racing with other threads")] - internal void ReportOutOfBandMessage(string msg, bool flush) - { - // msg == null is a signal to flush what's accumulated in the buffer - if (msg == null && flush) - { - if (!string.IsNullOrEmpty(m_deferredErrorInfo)) - { - WriteString(m_deferredErrorInfo); - m_deferredErrorInfo = String.Empty; - } - return; - } - - if (!msg.EndsWith(Environment.NewLine, StringComparison.Ordinal)) - msg = msg + Environment.NewLine; - - // send message to debugger without delay - System.Diagnostics.Debugger.Log(0, null, msg); - - m_deferredErrorInfo = m_deferredErrorInfo + msg; - if (flush) - { - // send message to the ETW listener if available - WriteString(m_deferredErrorInfo); - m_deferredErrorInfo = String.Empty; - } - } - -#if FEATURE_ACTIVITYSAMPLING - private void ReportActivitySamplingInfo(EventListener listener, SessionMask sessions) - { - Contract.Assert(listener == null || (uint)sessions == (uint)SessionMask.FromId(0)); - - for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId) - { - if (!sessions[perEventSourceSessionId]) - continue; - - ActivityFilter af; - if (listener == null) - { - EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId]; - Contract.Assert(etwSession != null); - af = etwSession.m_activityFilter; - } - else - { - af = listener.m_activityFilter; - } - - if (af == null) - continue; - - SessionMask m = new SessionMask(); - m[perEventSourceSessionId] = true; - - foreach (var t in af.GetFilterAsTuple(m_guid)) - { - WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: {1} = {2}", perEventSourceSessionId, t.Item1, t.Item2), m); - } - - bool participateInSampling = (listener == null) ? - m_activityFilteringForETWEnabled[perEventSourceSessionId] : - GetDispatcher(listener).m_activityFilteringEnabled; - WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: Activity Sampling support: {1}", - perEventSourceSessionId, participateInSampling ? "enabled" : "disabled"), m); - } - } -#endif // FEATURE_ACTIVITYSAMPLING - - // private instance state - private string m_name; // My friendly name (privided in ctor) - internal int m_id; // A small integer that is unique to this instance. - private Guid m_guid; // GUID representing the ETW eventSource to the OS. - internal volatile EventMetadata[] m_eventData; // None per-event data - private volatile byte[] m_rawManifest; // Bytes to send out representing the event schema - private readonly bool m_throwOnEventWriteErrors; // If a listener throws and error, should we catch it or not - - // Enabling bits - private bool m_eventSourceEnabled; // am I enabled (any of my events are enabled for any dispatcher) - internal EventLevel m_level; // higest level enabled by any output dispatcher - internal EventKeywords m_matchAnyKeyword; // the logical OR of all levels enabled by any output dispatcher (zero is a special case) meaning 'all keywords' - - // Dispatching state - internal volatile EventDispatcher m_Dispatchers; // Linked list of code:EventDispatchers we write the data to (we also do ETW specially) -#if FEATURE_MANAGED_ETW - private volatile OverideEventProvider m_provider; // This hooks up ETW commands to our 'OnEventCommand' callback -#endif - private bool m_completelyInited; // The EventSource constructor has returned without exception. - private bool m_deferedSendManifest; // We did not send the manifest in the startup path - private Exception m_lastCommandException; // If there was an exception during a command, this is it. - private Exception m_constructionException; // If there was an exception construction, this is it - private string m_deferredErrorInfo; // non-fatal error info accumulated during construction - - internal static uint s_currentPid; // current process id, used in synthesizing quasi-GUIDs - -#if FEATURE_ACTIVITYSAMPLING - private SessionMask m_curLiveSessions; // the activity-tracing aware sessions' bits - private EtwSession[] m_etwSessionIdMap; // the activity-tracing aware sessions - private List m_legacySessions; // the legacy ETW sessions listening to this source - internal long m_keywordTriggers; // a bit is set if it corresponds to a keyword that's part of an enabled triggering event - internal SessionMask m_activityFilteringForETWEnabled; // does THIS EventSource have activity filtering turned on for each ETW session - static internal Action s_activityDying; // Fires when something calls SetCurrentThreadToActivity() - // Also used to mark that activity tracing is on for some case -#endif // FEATURE_ACTIVITYSAMPLING - #endregion - } - - /// - /// An code:EventListener represents the target for all events generated by EventSources (that is - /// subclasses of code:EventSource), in the currnet appdomain. When a new EventListener is created - /// it is logically attached to all eventSources in that appdomain. When the EventListener is Disposed, then - /// it is disconnected from the event eventSources. Note that there is a internal list of STRONG references - /// to EventListeners, which means that relying on the lack of references ot EventListeners to clean up - /// EventListeners will NOT work. You must call EventListener.Dispose explicitly when a dispatcher is no - /// longer needed. - /// - /// Once created, EventListeners can enable or disable on a per-eventSource basis using verbosity levels - /// (code:EventLevel) and bitfields code:EventKeywords to further restrict the set of events to be sent - /// to the dispatcher. The dispatcher can also send arbitrary commands to a particular eventSource using the - /// 'SendCommand' method. The meaning of the commands are eventSource specific. - /// - /// The Null Guid (that is (new Guid()) has special meaning as a wildcard for 'all current eventSources in - /// the appdomain'. Thus it is relatively easy to turn on all events in the appdomain if desired. - /// - /// It is possible for there to be many EventListener's defined in a single appdomain. Each dispatcher is - /// logically independent of the other listeners. Thus when one dispatcher enables or disables events, it - /// affects only that dispatcher (other listeners get the events they asked for). It is possible that - /// commands sent with 'SendCommand' would do a semantic operation that would affect the other listeners - /// (like doing a GC, or flushing data ...), but this is the exception rather than the rule. - /// - /// Thus the model is that each EventSource keeps a list of EventListeners that it is sending events - /// to. Associated with each EventSource-dispatcher pair is a set of filtering criteria that determine for - /// that eventSource what events that dispatcher will recieve. - /// - /// Listeners receive the events on their 'OnEventWritten' method. Thus subclasses of EventListener must - /// override this method to do something useful with the data. - /// - /// In addition, when new eventSources are created, the 'OnEventSourceCreate' method is called. The - /// invariant associated with this callback is that every eventSource gets exactly one - /// 'OnEventSourceCreate' call for ever eventSource that can potentially send it log messages. In - /// particular when a EventListener is created, typically a series of OnEventSourceCreate' calls are - /// made to notify the new dispatcher of all the eventSources that existed before the EventListener was - /// created. - /// - /// - public abstract class EventListener : IDisposable - { - private static bool s_CreatingListener = false; - /// - /// Create a new EventListener in which all events start off truned off (use EnableEvents to turn - /// them on). - /// - protected EventListener() - { - lock (EventListenersLock) - { - // Disallow creating EventListener reentrancy. - if (s_CreatingListener) - throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback")); - - try - { - s_CreatingListener = true; - - // Add to list of listeners in the system, do this BEFORE firing the ‘OnEventSourceCreated’ so that - // Those added sources see this listener. - this.m_Next = s_Listeners; - s_Listeners = this; - - // Find all existing eventSources call OnEventSourceCreated to 'catchup' - // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback) - // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves - // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source - // is created. - WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray(); - - for (int i = 0; i < eventSourcesSnapshot.Length; i++) - { - WeakReference eventSourceRef = eventSourcesSnapshot[i]; - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource != null) - eventSource.AddListener(this); // This will cause the OnEventSourceCreated callback to fire. - } - - Validate(); - } - finally - { - s_CreatingListener = false; - } - } - } - /// - /// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because - /// there is an internal list of strong references to all EventListeners, calling 'Displose' directly - /// is the only way to actually make the listen die. Thus it is important that users of EventListener - /// call Dispose when they are done with their logging. - /// - public virtual void Dispose() - { - lock (EventListenersLock) - { - Contract.Assert(s_Listeners != null); - if (s_Listeners != null) - { - if (this == s_Listeners) - { - EventListener cur = s_Listeners; - s_Listeners = this.m_Next; - RemoveReferencesToListenerInEventSources(cur); - } - else - { - // Find 'this' from the s_Listeners linked list. - EventListener prev = s_Listeners; - for (; ; ) - { - EventListener cur = prev.m_Next; - if (cur == null) - break; - if (cur == this) - { - // Found our Listener, remove references to to it in the eventSources - prev.m_Next = cur.m_Next; // Remove entry. - RemoveReferencesToListenerInEventSources(cur); - break; - } - prev = cur; - } - } - } - Validate(); - } - } - // We don't expose a Dispose(bool), because the contract is that you don't have any non-syncronous - // 'cleanup' associated with this object - - /// Enable all events from the eventSource identified by 'eventSource' to the current dispatcher that have a - /// verbosity level of 'level' or lower. - /// - /// This call can have the effect of REDUCING the number of events sent to the dispatcher if 'level' - /// indicates a less verbose level than was previously enabled. - /// - /// This call never has an effect on other EventListeners. - /// - /// Returns 'true' if any eventSource could be found that matches 'eventSourceGuid' - /// - public void EnableEvents(EventSource eventSource, EventLevel level) - { - EnableEvents(eventSource, level, EventKeywords.None); - } - /// - /// Enable all events from the eventSource identified by 'eventSourceGuid' to the current dispatcher that have a - /// verbosity level of 'level' or lower and have a event keyword matching any of the bits in - /// 'machAnyKeyword'. - /// - /// This call can have the effect of REDUCING the number of events sent to the dispatcher if 'level' - /// indicates a less verbose level than was previously enabled or if 'machAnyKeyword' has fewer - /// keywords set than where previously set. - /// - /// If eventSourceGuid is Guid.Empty, then the affects all eventSources in the appdomain - /// - /// If eventSourceGuid is not Guid.Empty, this call has no effect on any other eventSources in the appdomain. - /// - /// This call never has an effect on other EventListeners. - /// - /// Returns 'true' if any eventSource could be found that matches 'eventSourceGuid' - /// - public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword) - { - EnableEvents(eventSource, level, matchAnyKeyword, null); - } - /// - /// Enable all events from the eventSource identified by 'eventSource' to the current dispatcher that have a - /// verbosity level of 'level' or lower and have a event keyword matching any of the bits in - /// 'machAnyKeyword' as well as any (eventSource specific) effect passing addingional 'key-value' arguments - /// 'arguments' might have. - /// - /// This call can have the effect of REDUCING the number of events sent to the dispatcher if 'level' - /// indicates a less verbose level than was previously enabled or if 'machAnyKeyword' has fewer - /// keywords set than where previously set. - /// - /// This call never has an effect on other EventListeners. - /// - public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword, IDictionary arguments) - { - if (eventSource == null) - { - throw new ArgumentNullException("eventSource"); - } - Contract.EndContractBlock(); - - eventSource.SendCommand(this, 0, 0, EventCommand.Update, true, level, matchAnyKeyword, arguments); - } - /// - /// Disables all events coming from eventSource identified by 'eventSource'. - /// - /// If eventSourceGuid is Guid.Empty, then the affects all eventSources in the appdomain - /// - /// This call never has an effect on other EventListeners. - /// - public void DisableEvents(EventSource eventSource) - { - if (eventSource == null) - { - throw new ArgumentNullException("eventSource"); - } - Contract.EndContractBlock(); - - eventSource.SendCommand(this, 0, 0, EventCommand.Update, false, EventLevel.LogAlways, EventKeywords.None, null); - } - - /// - /// This method is caleld whenever a new eventSource is 'attached' to the dispatcher. - /// This can happen for all existing EventSources when the EventListener is created - /// as well as for any EventSources that come into existance after the EventListener - /// has been created. - /// - /// These 'catch up' events are called during the construction of the EventListener. - /// Subclasses need to be prepared for that. - /// - /// In a multi-threaded environment, it is possible that 'OnEventWritten' callbacks - /// for a paritcular eventSource to occur BEFORE the OnEventSourceCreated is issued. - /// - /// - internal protected virtual void OnEventSourceCreated(EventSource eventSource) { } - /// - /// This method is called whenever an event has been written by a EventSource for which the EventListener - /// has enabled events. - /// - internal protected abstract void OnEventWritten(EventWrittenEventArgs eventData); - /// - /// EventSourceIndex is small non-negative integer (suitable for indexing in an array) - /// identifying EventSource. It is unique per-appdomain. Some EventListeners might find - /// it useful to store addditional information about each eventSource connected to it, - /// and EventSourceIndex allows this extra infomation to be efficiently stored in a - /// (growable) array (eg List(T)). - /// - static protected int EventSourceIndex(EventSource eventSource) { return eventSource.m_id; } - - #region private - /// - /// This routine adds newEventSource to the global list of eventSources, it also assigns the - /// ID to the eventSource (which is simply the oridinal in the global list). - /// - /// EventSources currently do not pro-actively remove themselves from this list. Instead - /// when eventSources's are GCed, the weak handle in this list naturally gets nulled, and - /// we will reuse the slot. Today this list never shrinks (but we do reuse entries - /// that are in the list). This seems OK since the expectation is that EventSources - /// tend to live for the lifetime of the appdomain anyway (they tend to be used in - /// global variables). - /// - /// - internal static void AddEventSource(EventSource newEventSource) - { - lock (EventListenersLock) - { - if (s_EventSources == null) - s_EventSources = new List(2); - - // Periodically search the list for existing entries to reuse, this avoids - // unbounded memory use if we keep recycling eventSources (an unlikely thing). - int newIndex = -1; - if (s_EventSources.Count % 64 == 63) // on every block of 64, fill up the block before continuing - { - int i = s_EventSources.Count; // Work from the top down. - while (0 < i) - { - --i; - WeakReference weakRef = s_EventSources[i]; - if (!weakRef.IsAlive) - { - newIndex = i; - weakRef.Target = newEventSource; - break; - } - } - } - if (newIndex < 0) - { - newIndex = s_EventSources.Count; - s_EventSources.Add(new WeakReference(newEventSource)); - } - newEventSource.m_id = newIndex; - - // Add every existing dispatcher to the new EventSource - for (EventListener listener = s_Listeners; listener != null; listener = listener.m_Next) - newEventSource.AddListener(listener); - - Validate(); - } - } - - /// - /// Helper used in code:Dispose that removes any references to 'listenerToRemove' in any of the - /// eventSources in the appdomain. - /// - /// The EventListenersLock must be held before calling this routine. - /// - private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove) - { - // Foreach existing EventSource in the appdomain - foreach (WeakReference eventSourceRef in s_EventSources) - { - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource != null) - { - // Is the first output dispatcher the dispatcher we are removing? - if (eventSource.m_Dispatchers.m_Listener == listenerToRemove) - eventSource.m_Dispatchers = eventSource.m_Dispatchers.m_Next; - else - { - // Remove 'listenerToRemove' from the eventSource.m_Dispatchers linked list. - EventDispatcher prev = eventSource.m_Dispatchers; - for (; ; ) - { - EventDispatcher cur = prev.m_Next; - if (cur == null) - { - Contract.Assert(false, "EventSource did not have a registered EventListener!"); - break; - } - if (cur.m_Listener == listenerToRemove) - { - prev.m_Next = cur.m_Next; // Remove entry. - break; - } - prev = cur; - } - } - } - } - } - - /// - /// Checks internal consistancy of EventSources/Listeners. - /// - [Conditional("DEBUG")] - internal static void Validate() - { - lock (EventListenersLock) - { - // Get all listeners - Dictionary allListeners = new Dictionary(); - EventListener cur = s_Listeners; - while (cur != null) - { - allListeners.Add(cur, true); - cur = cur.m_Next; - } - - // For all eventSources - int id = -1; - foreach (WeakReference eventSourceRef in s_EventSources) - { - id++; - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource == null) - continue; - Contract.Assert(eventSource.m_id == id, "Unexpected event source ID."); - - // None listeners on eventSources exist in the dispatcher list. - EventDispatcher dispatcher = eventSource.m_Dispatchers; - while (dispatcher != null) - { - Contract.Assert(allListeners.ContainsKey(dispatcher.m_Listener), "EventSource has a listener not on the global list."); - dispatcher = dispatcher.m_Next; - } - - // Every dispatcher is on Dispatcher List of every eventSource. - foreach (EventListener listener in allListeners.Keys) - { - dispatcher = eventSource.m_Dispatchers; - for (; ; ) - { - Contract.Assert(dispatcher != null, "Listener is not on all eventSources."); - if (dispatcher.m_Listener == listener) - break; - dispatcher = dispatcher.m_Next; - } - } - } - } - } - - /// - /// Gets a global lock that is intended to protect the code:s_Listeners linked list and the - /// code:s_EventSources WeakReference list. (We happen to use the s_EventSources list as - /// the lock object) - /// - internal static object EventListenersLock - { - get - { - if (s_EventSources == null) - Interlocked.CompareExchange(ref s_EventSources, new List(2), null); - return s_EventSources; - } - } - - // Instance fields - internal volatile EventListener m_Next; // These form a linked list in s_Listeners -#if FEATURE_ACTIVITYSAMPLING - internal ActivityFilter m_activityFilter; // If we are filtering by activity on this Listener, this keeps track of it. -#endif // FEATURE_ACTIVITYSAMPLING - - // static fields - internal static EventListener s_Listeners; // list of all EventListeners in the appdomain - internal static List s_EventSources; // all EventSources in the appdomain - #endregion - } - - /// - /// Passed to the code:EventSource.OnEventCommand callback - /// - public class EventCommandEventArgs : EventArgs - { - public EventCommand Command { get; private set; } - public IDictionary Arguments { get; private set; } - - public bool EnableEvent(int eventId) - { - if (Command != EventCommand.Enable && Command != EventCommand.Disable) - throw new InvalidOperationException(); - return eventSource.EnableEventForDispatcher(dispatcher, eventId, true); - } - public bool DisableEvent(int eventId) - { - if (Command != EventCommand.Enable && Command != EventCommand.Disable) - throw new InvalidOperationException(); - return eventSource.EnableEventForDispatcher(dispatcher, eventId, false); - } - - #region private - - internal EventCommandEventArgs(EventCommand command, IDictionary arguments, EventSource eventSource, EventDispatcher dispatcher) - { - this.Command = command; - this.Arguments = arguments; - this.eventSource = eventSource; - this.dispatcher = dispatcher; - } - - internal EventSource eventSource; - internal EventDispatcher dispatcher; - - #endregion - } - - /// - /// code:EventWrittenEventArgs is passed when the callback given in code:EventListener.OnEventWritten is - /// fired. - /// - public class EventWrittenEventArgs : EventArgs - { - public int EventId { get; internal set; } - public Guid ActivityId - { - [System.Security.SecurityCritical] - get { return EventSource.CurrentThreadActivityId; } - } - public Guid RelatedActivityId - { - [System.Security.SecurityCritical] - get; - internal set; - } - public ReadOnlyCollection Payload { get; internal set; } - public EventSource EventSource { get { return m_eventSource; } } - public EventKeywords Keywords { get { return (EventKeywords)m_eventSource.m_eventData[EventId].Descriptor.Keywords; } } - public EventOpcode Opcode { get { return (EventOpcode)m_eventSource.m_eventData[EventId].Descriptor.Opcode; } } - public EventTask Task { get { return (EventTask)m_eventSource.m_eventData[EventId].Descriptor.Task; } } - public string Message - { - get - { - if (m_message != null) - return m_message; - else - return m_eventSource.m_eventData[EventId].Message; - } - internal set - { - m_message = value; - } - } - -#if FEATURE_MANAGED_ETW_CHANNELS - public EventChannel Channel { get { return (EventChannel) m_eventSource.m_eventData[EventId].Descriptor.Channel; }} -#endif - public byte Version { get { return m_eventSource.m_eventData[EventId].Descriptor.Version; } } - public EventLevel Level - { - get - { - if ((uint)EventId >= (uint)m_eventSource.m_eventData.Length) - return EventLevel.LogAlways; - return (EventLevel)m_eventSource.m_eventData[EventId].Descriptor.Level; - } - } - - #region private - internal EventWrittenEventArgs(EventSource eventSource) - { - m_eventSource = eventSource; - } - private string m_message; - private EventSource m_eventSource; - #endregion - } - - [AttributeUsage(AttributeTargets.Class)] - public sealed class EventSourceAttribute : Attribute - { - public string Name { get; set; } - public string Guid { get; set; } - - /// - /// EventSources support localization of events. The names used for events, opcodes, tasks, keyworks and maps - /// can be localized to several languages if desired. This works by creating a ResX style string table - /// (by simply adding a 'Resource File' to your project). This resource file is given a name e.g. - /// 'DefaultNameSpace.ResourceFileName' which can be passed to the ResourceManager constructor to read the - /// resoruces. This name is the value of the LocalizationResources property. - /// - /// LocalizationResources property is non-null, then EventSource will look up the localized strings for events by - /// using the following resource naming scheme - /// - /// event_EVENTNAME - /// task_TASKNAME - /// keyword_KEYWORDNAME - /// map_MAPNAME - /// - /// where the capitpalized name is the name of the event, task, keywork, or map value that should be localized. - /// Note that the localized string for an event corresponds to the Messsage string, and can have {0} values - /// which represent the payload values. - /// - public string LocalizationResources { get; set; } - } - - /// - /// None instance methods in a class that subclasses code:EventSource that and return void are - /// assumed by default to be methods that generate an event. Enough information can be deduced from the - /// name of the method and its signature to generate basic schema information for the event. The - /// code:EventAttribute allows you to specify additional event schema information for an event if - /// desired. - /// - [AttributeUsage(AttributeTargets.Method)] - public sealed class EventAttribute : Attribute - { - public EventAttribute(int eventId) { this.EventId = eventId; Level = EventLevel.Informational; } - public int EventId { get; private set; } - public EventLevel Level { get; set; } - public EventKeywords Keywords { get; set; } - public EventOpcode Opcode { get; set; } - public EventTask Task { get; set; } -#if FEATURE_MANAGED_ETW_CHANNELS - public EventChannel Channel { get; set; } -#endif - public byte Version { get; set; } - - /// - /// This is also used for TraceSource compatabilty. If code:EventSource.TraceSourceSupport is - /// on events will also be logged a tracesource with the same name as the eventSource. If this - /// property is set then the payload will go to code:TraceSource.TraceEvent, and this string - /// will be used as the message. If this property is not set not set it goes to - /// code:TraceSource.TraceData. You can use standard .NET substitution operators (eg {1}) in - /// the string and they will be replaced with the 'ToString()' of the cooresponding part of the - /// event payload. - /// - public string Message { get; set; } - } - - /// - /// By default all instance methods in a class that subclasses code:EventSource that and return - /// void are assumed to be methods that generate an event. This default can be overriden by specifying - /// the code:NonEventAttribute - /// - [AttributeUsage(AttributeTargets.Method)] - public sealed class NonEventAttribute : Attribute - { - public NonEventAttribute() { } - } - - - // -#if FEATURE_MANAGED_ETW_CHANNELS - [AttributeUsage(AttributeTargets.Field)] - public class ChannelAttribute : Attribute - { - public bool Enabled { get; set; } - public string Isolation { get; set; } - /// - /// Legal values are in ChannelTypes - /// - public string Type { get; set; } - - // - public string ImportChannel { get; set; } - // - - } - - // - - public static class ChannelTypes - { - public const string Admin = "Admin"; - public const string Operational = "Operational"; - public const string Analytic = "Analytic"; - public const string Debug = "Debug"; - } -#endif - - public enum EventCommand - { - Update = 0, - SendManifest = -1, - Enable = -2, - Disable = -3 - }; - - - #region private classes - -#if FEATURE_ACTIVITYSAMPLING - - /// - /// ActivityFilter is a helper structure that is used to keep track of run-time state - /// associated with activity filtering. It is 1-1 with EventListeners (logically - /// every listener has one of these, however we actually allocate them lazily), as well - /// as 1-to-1 with tracing-aware EtwSessions. - /// - /// This structure also keeps track of the sampling counts associated with 'trigger' - /// events. Because these trigger events are rare, and you typically only have one of - /// them, we store them here as a linked list. - /// - internal sealed class ActivityFilter : IDisposable - { - /// - /// Disable all activity filtering for the listener associated with 'filterList', - /// (in the session associated with it) that is triggered by any event in 'source'. - /// - public static void DisableFilter(ref ActivityFilter filterList, EventSource source) - { - Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); - - if (filterList == null) - return; - - ActivityFilter cur; - // Remove it from anywhere in the list (except the first element, which has to - // be treated specially) - ActivityFilter prev = filterList; - cur = prev.m_next; - while (cur != null) - { - if (cur.m_providerGuid == source.Guid) - { - // update TriggersActivityTracking bit - if (cur.m_eventId >= 0 && cur.m_eventId < source.m_eventData.Length) - --source.m_eventData[cur.m_eventId].TriggersActivityTracking; - - // Remove it from the linked list. - prev.m_next = cur.m_next; - // dispose of the removed node - cur.Dispose(); - // update cursor - cur = prev.m_next; - } - else - { - // update cursors - prev = cur; - cur = prev.m_next; - } - } - - // Sadly we have to treat the first element specially in linked list removal in C# - if (filterList.m_providerGuid == source.Guid) - { - // update TriggersActivityTracking bit - if (filterList.m_eventId >= 0 && filterList.m_eventId < source.m_eventData.Length) - --source.m_eventData[filterList.m_eventId].TriggersActivityTracking; - - // We are the first element in the list. - var first = filterList; - filterList = first.m_next; - // dispose of the removed node - first.Dispose(); - } - // the above might have removed the one ActivityFilter in the session that contains the - // cleanup delegate; re-create the delegate if needed - if (filterList != null) - { - EnsureActivityCleanupDelegate(filterList); - } - } - - /// - /// Currently this has "override" semantics. We first disable all filters - /// associated with 'source', and next we add new filters for each entry in the - /// string 'startEvents'. participateInSampling specifies whether non-startEvents - /// always trigger or only trigger when current activity is 'active'. - /// - public static void UpdateFilter( - ref ActivityFilter filterList, - EventSource source, - int perEventSourceSessionId, - string startEvents) - { - Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); - - // first remove all filters associated with 'source' - DisableFilter(ref filterList, source); - - if (!string.IsNullOrEmpty(startEvents)) - { - // ActivitySamplingStartEvents is a space-separated list of Event:Frequency pairs. - // The Event may be specified by name or by ID. Errors in parsing such a pair - // result in the error being reported to the listeners, and the pair being ignored. - // E.g. "CustomActivityStart:1000 12:10" specifies that for event CustomActivityStart - // we should initiate activity tracing once every 1000 events, *and* for event ID 12 - // we should initiate activity tracing once every 10 events. - string[] activityFilterStrings = startEvents.Split(' '); - - for (int i = 0; i < activityFilterStrings.Length; ++i) - { - string activityFilterString = activityFilterStrings[i]; - int sampleFreq = 1; - int eventId = -1; - int colonIdx = activityFilterString.IndexOf(':'); - if (colonIdx < 0) - { - source.ReportOutOfBandMessage("ERROR: Invalid ActivitySamplingStartEvent specification: " + - activityFilterString, false); - // ignore failure... - continue; - } - string sFreq = activityFilterString.Substring(colonIdx + 1); - if (!int.TryParse(sFreq, out sampleFreq)) - { - source.ReportOutOfBandMessage("ERROR: Invalid sampling frequency specification: " + sFreq, false); - continue; - } - activityFilterString = activityFilterString.Substring(0, colonIdx); - if (!int.TryParse(activityFilterString, out eventId)) - { - // reset eventId - eventId = -1; - // see if it's an event name - for (int j = 0; j < source.m_eventData.Length; j++) - { - EventSource.EventMetadata[] ed = source.m_eventData; - if (ed[j].Name != null && ed[j].Name.Length == activityFilterString.Length && - string.Compare(ed[j].Name, activityFilterString, StringComparison.OrdinalIgnoreCase) == 0) - { - eventId = ed[j].Descriptor.EventId; - break; - } - } - } - if (eventId < 0 || eventId >= source.m_eventData.Length) - { - source.ReportOutOfBandMessage("ERROR: Invalid eventId specification: " + activityFilterString, false); - continue; - } - EnableFilter(ref filterList, source, perEventSourceSessionId, eventId, sampleFreq); - } - } - } - - /// - /// Returns the first ActivityFilter from 'filterList' corresponding to 'source'. - /// - public static ActivityFilter GetFilter(ActivityFilter filterList, EventSource source) - { - for (var af = filterList; af != null; af = af.m_next) - { - if (af.m_providerGuid == source.Guid && af.m_samplingFreq != -1) - return af; - } - return null; - } - - /// - /// Returns a session mask representing all sessions in which the activity - /// associated with the current thread is allowed through the activity filter. - /// If 'triggeringEvent' is true the event MAY be a triggering event. Ideally - /// most of the time this is false as you can guarentee this event is NOT a - /// triggering event. If 'triggeringEvent' is true, then it checks the - /// 'EventSource' and 'eventID' of the event being logged to see if it is actually - /// a trigger. If so it activates the current activity. - /// - /// If 'childActivityID' is present, it will be added to the active set if the - /// current activity is active. - /// - [SecurityCritical] - unsafe public static bool PassesActivityFilter( - ActivityFilter filterList, - Guid* childActivityID, - bool triggeringEvent, - EventSource source, - int eventId) - { - Contract.Assert(filterList != null && filterList.m_activeActivities != null); - bool shouldBeLogged = false; - if (triggeringEvent) - { - for (ActivityFilter af = filterList; af != null; af = af.m_next) - { - if (eventId == af.m_eventId && source.Guid == af.m_providerGuid) - { - // Update the sampling count with wrap-around - int curSampleCount, newSampleCount; - do - { - curSampleCount = af.m_curSampleCount; - if (curSampleCount <= 1) - newSampleCount = af.m_samplingFreq; // Wrap around, counting down to 1 - else - newSampleCount = curSampleCount - 1; - } - while (Interlocked.CompareExchange(ref af.m_curSampleCount, newSampleCount, curSampleCount) != curSampleCount); - // If we hit zero, then start tracking the activity. - if (curSampleCount <= 1) - { - Guid currentActivityId = EventSource.InternalCurrentThreadActivityId; - Tuple startId; - // only add current activity if it's not already a root activity - if (!af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId)) - { - // EventSource.OutputDebugString(string.Format(" PassesAF - Triggering(session {0}, evt {1})", af.m_perEventSourceSessionId, eventId)); - shouldBeLogged = true; - af.m_activeActivities[currentActivityId] = Environment.TickCount; - af.m_rootActiveActivities[currentActivityId] = Tuple.Create(source.Guid, eventId); - } - } - else - { - // a start event following a triggering start event - Guid currentActivityId = EventSource.InternalCurrentThreadActivityId; - Tuple startId; - // only remove current activity if we added it - if (af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId) && - startId.Item1 == source.Guid && startId.Item2 == eventId) - { - // EventSource.OutputDebugString(string.Format("Activity dying: {0} -> StartEvent({1})", currentActivityId, eventId)); - // remove activity only from current logging scope (af) - int dummy; - af.m_activeActivities.TryRemove(currentActivityId, out dummy); - } - } - break; - } - } - } - - var activeActivities = GetActiveActivities(filterList); - if (activeActivities != null) - { - // if we hadn't already determined this should be logged, test further - if (!shouldBeLogged) - { - shouldBeLogged = !activeActivities.IsEmpty && - activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId); - } - if (shouldBeLogged && childActivityID != null && - ((EventOpcode)source.m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send)) - { - FlowActivityIfNeeded(filterList, null, childActivityID); - // EventSource.OutputDebugString(string.Format(" PassesAF - activity {0}", *childActivityID)); - } - } - // EventSource.OutputDebugString(string.Format(" PassesAF - shouldBeLogged(evt {0}) = {1:x}", eventId, shouldBeLogged)); - return shouldBeLogged; - } - - [System.Security.SecuritySafeCritical] - public static bool IsCurrentActivityActive(ActivityFilter filterList) - { - var activeActivities = GetActiveActivities(filterList); - if (activeActivities != null && - activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId)) - return true; - - return false; - } - - /// - /// For the EventListener/EtwSession associated with 'filterList', add 'childActivityid' - /// to list of active activities IF 'currentActivityId' is also active. Passing in a null - /// value for 'currentActivityid' is an indication tha caller has already verified - /// that the current activity is active. - /// - [SecurityCritical] - unsafe public static void FlowActivityIfNeeded(ActivityFilter filterList, Guid *currentActivityId, Guid *childActivityID) - { - Contract.Assert(childActivityID != null); - - var activeActivities = GetActiveActivities(filterList); - Contract.Assert(activeActivities != null); - - // take currentActivityId == null to mean we *know* the current activity is "active" - if (currentActivityId != null && !activeActivities.ContainsKey(*currentActivityId)) - return; - - if (activeActivities.Count > MaxActivityTrackCount) - { - TrimActiveActivityStore(activeActivities); - // make sure current activity is still in the set: - activeActivities[EventSource.InternalCurrentThreadActivityId] = Environment.TickCount; - } - // add child activity to list of actives - activeActivities[*childActivityID] = Environment.TickCount; - - } - - /// - /// - public static void UpdateKwdTriggers(ActivityFilter activityFilter, Guid sourceGuid, EventSource source, EventKeywords sessKeywords) - { - for (var af = activityFilter; af != null; af = af.m_next) - { - if ((sourceGuid == af.m_providerGuid) && - (source.m_eventData[af.m_eventId].TriggersActivityTracking > 0 || - ((EventOpcode)source.m_eventData[af.m_eventId].Descriptor.Opcode == EventOpcode.Send))) - { - // we could be more precise here, if we tracked 'anykeywords' per session - source.m_keywordTriggers |= (source.m_eventData[af.m_eventId].Descriptor.Keywords & (long)sessKeywords); - } - } - } - - /// - /// For the EventSource specified by 'sourceGuid' and the EventListener/EtwSession - /// associated with 'this' ActivityFilter list, return configured sequence of - /// [eventId, sampleFreq] pairs that defines the sampling policy. - /// - public IEnumerable> GetFilterAsTuple(Guid sourceGuid) - { - for (ActivityFilter af = this; af != null; af = af.m_next) - { - if (af.m_providerGuid == sourceGuid) - yield return Tuple.Create(af.m_eventId, af.m_samplingFreq); - } - } - - /// - /// The cleanup being performed consists of removing the m_myActivityDelegate from - /// the static s_activityDying, therefore allowing the ActivityFilter to be reclaimed. - /// - public void Dispose() - { - Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); - // m_myActivityDelegate is still alive (held by the static EventSource.s_activityDying). - // Therefore we are ok to take a dependency on m_myActivityDelegate being valid even - // during the finalization of the ActivityFilter - if (m_myActivityDelegate != null) - { - EventSource.s_activityDying = (Action)Delegate.Remove(EventSource.s_activityDying, m_myActivityDelegate); - m_myActivityDelegate = null; - } - } - - #region private - - /// - /// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever - /// 'samplingFreq' times the event fires. You can have several of these forming a - /// linked list. - /// - private ActivityFilter(EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq, ActivityFilter existingFilter = null) - { - m_providerGuid = source.Guid; - m_perEventSourceSessionId = perEventSourceSessionId; - m_eventId = eventId; - m_samplingFreq = samplingFreq; - m_next = existingFilter; - - Contract.Assert(existingFilter == null || - (existingFilter.m_activeActivities == null) == (existingFilter.m_rootActiveActivities == null)); - - // if this is the first filter we add for this session, we need to create a new - // table of activities. m_activeActivities is common across EventSources in the same - // session - ConcurrentDictionary activeActivities = null; - if (existingFilter == null || - (activeActivities = GetActiveActivities(existingFilter)) == null) - { - m_activeActivities = new ConcurrentDictionary(); - m_rootActiveActivities = new ConcurrentDictionary>(); - - // Add a delegate to the 'SetCurrentThreadToActivity callback so that I remove 'dead' activities - m_myActivityDelegate = GetActivityDyingDelegate(this); - EventSource.s_activityDying = (Action)Delegate.Combine(EventSource.s_activityDying, m_myActivityDelegate); - } - else - { - m_activeActivities = activeActivities; - m_rootActiveActivities = existingFilter.m_rootActiveActivities; - } - - } - - /// - /// Ensure there's at least one ActivityFilter in the 'filterList' that contains an - /// activity-removing delegate for the listener/session associated with 'filterList'. - /// - private static void EnsureActivityCleanupDelegate(ActivityFilter filterList) - { - if (filterList == null) - return; - - for (ActivityFilter af = filterList; af != null; af = af.m_next) - { - if (af.m_myActivityDelegate != null) - return; - } - - // we didn't find a delegate - filterList.m_myActivityDelegate = GetActivityDyingDelegate(filterList); - EventSource.s_activityDying = (Action)Delegate.Combine(EventSource.s_activityDying, filterList.m_myActivityDelegate); - } - - /// - /// Builds the delegate to be called when an activity is dying. This is responsible - /// for performing whatever cleanup is needed for the ActivityFilter list passed in. - /// This gets "added" to EventSource.s_activityDying and ends up being called from - /// EventSource.SetCurrentThreadActivityId and ActivityFilter.PassesActivityFilter. - /// - /// The delegate to be called when an activity is dying - private static Action GetActivityDyingDelegate(ActivityFilter filterList) - { - return (Guid oldActivity) => - { - int dummy; - filterList.m_activeActivities.TryRemove(oldActivity, out dummy); - Tuple dummyTuple; - filterList.m_rootActiveActivities.TryRemove(oldActivity, out dummyTuple); - }; - } - - /// - /// Enables activity filtering for the listener associated with 'filterList', triggering on - /// the event 'eventID' from 'source' with a sampling frequency of 'samplingFreq' - /// - /// if 'eventID' is out of range (e.g. negative), it means we are not triggering (but we are - /// activitySampling if something else triggered). - /// - /// true if activity sampling is enabled the samplingFreq is non-zero - private static bool EnableFilter(ref ActivityFilter filterList, EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq) - { - Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); - Contract.Assert(samplingFreq > 0); - Contract.Assert(eventId >= 0); - - filterList = new ActivityFilter(source, perEventSourceSessionId, eventId, samplingFreq, filterList); - - // Mark the 'quick Check' that indicates this is a trigger event. - // If eventId is out of range then this mark is not done which has the effect of ignoring - // the trigger. - if (0 <= eventId && eventId < source.m_eventData.Length) - ++source.m_eventData[eventId].TriggersActivityTracking; - - return true; - } - - /// - /// Normally this code never runs, it is here just to prevent run-away resource usage. - /// - private static void TrimActiveActivityStore(ConcurrentDictionary activities) - { - if (activities.Count > MaxActivityTrackCount) - { - // Remove half of the oldest activity ids. - var keyValues = activities.ToArray(); - var tickNow = Environment.TickCount; - - // Sort by age, taking into account wrap-around. As long as x and y are within - // 23 days of now then (0x7FFFFFFF & (tickNow - x.Value)) is the delta (even if - // TickCount wraps). I then sort by DESCENDING age. (that is oldest value first) - Array.Sort(keyValues, (x, y) => (0x7FFFFFFF & (tickNow - y.Value)) - (0x7FFFFFFF & (tickNow - x.Value))); - for (int i = 0; i < keyValues.Length / 2; i++) - { - int dummy; - activities.TryRemove(keyValues[i].Key, out dummy); - } - } - } - - private static ConcurrentDictionary GetActiveActivities( - ActivityFilter filterList) - { - for (ActivityFilter af = filterList; af != null; af = af.m_next) - { - if (af.m_activeActivities != null) - return af.m_activeActivities; - } - return null; - } - - // m_activeActivities always points to the sample dictionary for EVERY ActivityFilter - // in the m_next list. The 'int' value in the m_activities set is a timestamp - // (Environment.TickCount) of when the entry was put in the system and is used to - // remove 'old' entries that if the set gets too big. - ConcurrentDictionary m_activeActivities; - - // m_rootActiveActivities holds the "root" active activities, i.e. the activities - // that were marked as active because a Start event fired on them. We need to keep - // track of these to enable sampling in the scenario of an app's main thread that - // never explicitly sets distinct activity IDs as it executes. To handle these - // situations we manufacture a Guid from the thread's ID, and: - // (a) we consider the firing of a start event when the sampling counter reaches - // zero to mark the beginning of an interesting activity, and - // (b) we consider the very next firing of the same start event to mark the - // ending of that activity. - // We use a ConcurrentDictionary to avoid taking explicit locks. - // The key (a guid) represents the activity ID of the root active activity - // The value is made up of the Guid of the event provider and the eventId of - // the start event. - ConcurrentDictionary> m_rootActiveActivities; - Guid m_providerGuid; // We use the GUID rather than object identity because we don't want to keep the eventSource alive - int m_eventId; // triggering event - int m_samplingFreq; // Counter reset to this when it hits 0 - int m_curSampleCount; // We count down to 0 and then activate the activity. - int m_perEventSourceSessionId; // session ID bit for ETW, 0 for EventListeners - - const int MaxActivityTrackCount = 100000; // maximum number of tracked activities - - ActivityFilter m_next; // We create a linked list of these - Action m_myActivityDelegate; - #endregion - }; - - - /// - /// An EtwSession instance represents an activity-tracing-aware ETW session. Since these - /// are limited to 8 concurrent sessions per machine (currently) we're going to store - /// the active ones in a singly linked list. - /// - internal class EtwSession - { - public static EtwSession GetEtwSession(int etwSessionId, bool bCreateIfNeeded = false) - { - if (etwSessionId < 0) - return null; - - EtwSession etwSession; - foreach(var wrEtwSession in s_etwSessions) - { - if (wrEtwSession.TryGetTarget(out etwSession) && etwSession.m_etwSessionId == etwSessionId) - return etwSession; - } - - if (!bCreateIfNeeded) - return null; - - if (s_etwSessions == null) - s_etwSessions = new List>(); - - etwSession = new EtwSession(etwSessionId); - s_etwSessions.Add(new WeakReference(etwSession)); - if (s_etwSessions.Count > s_thrSessionCount) - TrimGlobalList(); - - return etwSession; - - } - - public static void RemoveEtwSession(EtwSession etwSession) - { - Contract.Assert(etwSession != null); - if (s_etwSessions == null) - return; - - s_etwSessions.RemoveAll((wrEtwSession) => - { - EtwSession session; - return wrEtwSession.TryGetTarget(out session) && - (session.m_etwSessionId == etwSession.m_etwSessionId); - }); - - if (s_etwSessions.Count > s_thrSessionCount) - TrimGlobalList(); - } - - private static void TrimGlobalList() - { - if (s_etwSessions == null) - return; - - s_etwSessions.RemoveAll((wrEtwSession) => - { - EtwSession session; - return !wrEtwSession.TryGetTarget(out session); - }); - } - - private EtwSession(int etwSessionId) - { - m_etwSessionId = etwSessionId; - } - - public readonly int m_etwSessionId; // ETW session ID (as retrieved by EventProvider) - public ActivityFilter m_activityFilter; // all filters enabled for this session - - private static List> s_etwSessions = new List>(); - private const int s_thrSessionCount = 16; - } - -#endif // FEATURE_ACTIVITYSAMPLING - - // holds a bitfield representing a session mask - /// - /// A SessionMask represents a set of (at most MAX) sessions as a bit mask. The perEventSourceSessionId - /// is the index in the SessionMask of the bit that will be set. These can translate to - /// EventSource's reserved keywords bits using the provided ToEventKeywords() and - /// FromEventKeywords() methods. - /// - internal struct SessionMask - { - public SessionMask(SessionMask m) - { m_mask = m.m_mask; } - - public SessionMask(uint mask = 0) - { m_mask = mask & MASK; } - - public bool IsEqualOrSupersetOf(SessionMask m) - { - return (this.m_mask | m.m_mask) == this.m_mask; - } - - public static SessionMask All - { - get { return new SessionMask(MASK); } - } - - public static SessionMask FromId(int perEventSourceSessionId) - { - Contract.Assert(perEventSourceSessionId < MAX); - return new SessionMask((uint) 1 << perEventSourceSessionId); - } - - public ulong ToEventKeywords() - { - return (ulong)m_mask << SHIFT_SESSION_TO_KEYWORD; - } - - public static SessionMask FromEventKeywords(ulong m) - { - return new SessionMask((uint)(m >> SHIFT_SESSION_TO_KEYWORD)); - } - - public bool this[int perEventSourceSessionId] - { - get - { - Contract.Assert(perEventSourceSessionId < MAX); - return (m_mask & (1 << perEventSourceSessionId)) != 0; - } - set - { - Contract.Assert(perEventSourceSessionId < MAX); - if (value) m_mask |= ((uint) 1 << perEventSourceSessionId); - else m_mask &= ~((uint) 1 << perEventSourceSessionId); - } - } - - public static SessionMask operator | (SessionMask m1, SessionMask m2) - { - return new SessionMask(m1.m_mask | m2.m_mask); - } - - public static SessionMask operator & (SessionMask m1, SessionMask m2) - { - return new SessionMask(m1.m_mask & m2.m_mask); - } - - public static SessionMask operator ^ (SessionMask m1, SessionMask m2) - { - return new SessionMask(m1.m_mask ^ m2.m_mask); - } - - public static SessionMask operator ~(SessionMask m) - { - return new SessionMask(MASK & ~(m.m_mask)); - } - - public static explicit operator ulong(SessionMask m) - { return m.m_mask; } - - public static explicit operator uint(SessionMask m) - { return m.m_mask; } - - private uint m_mask; - - internal const int SHIFT_SESSION_TO_KEYWORD = 44; // bits 44-47 inclusive are reserved - internal const uint MASK = 0x0fU; // the mask of 4 reserved bits - internal const uint MAX = 4; // maximum number of simultaneous ETW sessions supported - // (equals bitcount(MASK)) - } - - /// - /// code:EventDispatchers are a simple 'helper' structure that holds the filtering state - /// (m_EventEnabled) for a particular EventSource X EventListener tuple - /// - /// Thus a single EventListener may have many EventDispatchers (one for every EventSource - /// that that EventListener has activate) and a Single EventSource may also have many - /// event Dispatchers (one for every EventListener that has activated it). - /// - /// Logically a particular EventDispatcher belongs to exactly one EventSource and exactly - /// one EventListener (alhtough EventDispatcher does not 'remember' the EventSource it is - /// associated with. - /// - internal class EventDispatcher - { - internal EventDispatcher(EventDispatcher next, bool[] eventEnabled, EventListener listener) - { - m_Next = next; - m_EventEnabled = eventEnabled; - m_Listener = listener; - } - - // Instance fields - readonly internal EventListener m_Listener; // The dispatcher this entry is for - internal bool[] m_EventEnabled; // For every event in a the eventSource, is it enabled? -#if FEATURE_ACTIVITYSAMPLING - internal bool m_activityFilteringEnabled; // does THIS EventSource have activity filtering turned on for this listener? -#endif // FEATURE_ACTIVITYSAMPLING - - // Only guarenteed to exist after a InsureInit() - internal EventDispatcher m_Next; // These form a linked list in code:EventSource.m_Dispatchers - // Of all listeners for that eventSource. - } - - /// - /// ManifestBuilder is designed to isolate the details of the message of the event from the - /// rest of EventSource. This one happens to create XML. - /// - internal class ManifestBuilder - { - /// - /// Build a manifest for 'providerName' with the given GUID, which will be packaged into 'dllName'. - /// 'resources, is a resource manager. If specified all messsages are localized using that manager. - /// - public ManifestBuilder(string providerName, Guid providerGuid, string dllName, ResourceManager resources) - { -#if FEATURE_MANAGED_ETW_CHANNELS - this.providerName = providerName; -#endif - this.resources = resources; - sb = new StringBuilder(); - events = new StringBuilder(); - templates = new StringBuilder(); - opcodeTab = new Dictionary(); - stringTab = new Dictionary(); - - sb.AppendLine(""); - sb.AppendLine(" "); - sb.AppendLine(" "); - sb.Append("").AppendLine(); - } - - public void AddOpcode(string name, int value) - { - opcodeTab[value] = name; - } - public void AddTask(string name, int value) - { - if (taskTab == null) - taskTab = new Dictionary(); - taskTab[value] = name; - } - public void AddKeyword(string name, ulong value) - { - if ((value & (value - 1)) != 0) // Is it a power of 2? - throw new ArgumentException(Environment.GetResourceString("EventSource_KeywordNeedPowerOfTwo", value.ToString("x", CultureInfo.CurrentCulture), name)); - if (keywordTab == null) - keywordTab = new Dictionary(); - keywordTab[value] = name; - } - -#if FEATURE_MANAGED_ETW_CHANNELS - /// - /// Add a channel. channelAttribute can be null - /// - public void AddChannel(string name, int value, ChannelAttribute channelAttribute) - { - if (channelTab == null) - channelTab = new Dictionary(); - channelTab[value] = new ChannelInfo { Name = name, Attribs = channelAttribute }; - } -#endif - public void StartEvent(string eventName, EventAttribute eventAttribute) - { - Contract.Assert(numParams == 0); - Contract.Assert(templateName == null); - templateName = eventName + "Args"; - numParams = 0; - - events.Append(" ").AppendLine(); - numParams++; - templates.Append(" (); - if (!mapsTab.ContainsKey(type.Name)) - mapsTab.Add(type.Name, type); // Remember that we need to dump the type enumeration - } - - templates.Append("/>").AppendLine(); - } - public void EndEvent() - { - if (numParams > 0) - { - templates.Append(" ").AppendLine(); - events.Append(" template=\"").Append(templateName).Append("\""); - } - events.Append("/>").AppendLine(); - - templateName = null; - numParams = 0; - } - - public byte[] CreateManifest() - { - string str = CreateManifestString(); - return Encoding.UTF8.GetBytes(str); - } - private string CreateManifestString() - { - -#if FEATURE_MANAGED_ETW_CHANNELS - // Write out the channels - if (channelTab != null) - { - sb.Append(" ").AppendLine(); - var sortedChannels = new List(channelTab.Keys); - sortedChannels.Sort(); - foreach (int channel in sortedChannels) - { - var channelInfo = channelTab[channel]; - - // - string channelType = null; - string elementName = "channel"; - bool enabled = false; - string isolation = null; - string fullName = null; - if (channelInfo.Attribs != null) - { - var attribs = channelInfo.Attribs; - channelType = attribs.Type; - if (attribs.ImportChannel != null) - { - fullName = attribs.ImportChannel; - elementName = "importChannel"; - } - enabled = attribs.Enabled; - isolation = attribs.Isolation; - } - if (fullName == null) - fullName = providerName + "/" + channelType; - - - sb.Append(" <").Append(elementName); - sb.Append(" chid=\"").Append(channelInfo.Name).Append("\""); - sb.Append(" name=\"").Append(fullName).Append("\""); - sb.Append(" value=\"").Append(channel).Append("\""); - if (elementName == "channel") // not applicable to importChannels. - { - if (channelType != null) - sb.Append(" type=\"").Append(channelType).Append("\""); - sb.Append(" enabled=\"").Append(enabled.ToString()).Append("\""); - if (isolation != null) - sb.Append(" isolation=\"").Append(isolation).Append("\""); - } - sb.Append("/>").AppendLine(); - } - sb.Append(" ").AppendLine(); - } -#endif - - // Write out the tasks - if (taskTab != null) - { - - sb.Append(" ").AppendLine(); - var sortedTasks = new List(taskTab.Keys); - sortedTasks.Sort(); - foreach (int task in sortedTasks) - { - sb.Append(" ").AppendLine(); - } - sb.Append(" ").AppendLine(); - } - - // Write out the maps - if (mapsTab != null) - { - sb.Append(" ").AppendLine(); - foreach (Type enumType in mapsTab.Values) - { - string mapKind = EventSource.GetCustomAttributeHelper(enumType, typeof(FlagsAttribute)) != null ? "bitMap" : "valueMap"; - sb.Append(" <").Append(mapKind).Append(" name=\"").Append(enumType.Name).Append("\">").AppendLine(); - - // write out each enum value - FieldInfo[] staticFields = enumType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static); - foreach (FieldInfo staticField in staticFields) - { - object constantValObj = staticField.GetRawConstantValue(); - if (constantValObj != null) - { - string hexStr = null; - if (constantValObj is int) - hexStr = ((int)constantValObj).ToString("x", CultureInfo.InvariantCulture); - else if (constantValObj is long) - hexStr = ((long)constantValObj).ToString("x", CultureInfo.InvariantCulture); - sb.Append(" ").AppendLine(); - } - } - sb.Append(" ").AppendLine(); - } - sb.Append(" ").AppendLine(); - } - - // Write out the opcodes - sb.Append(" ").AppendLine(); - var sortedOpcodes = new List(opcodeTab.Keys); - sortedOpcodes.Sort(); - foreach (int opcode in sortedOpcodes) - { - sb.Append(" ").AppendLine(); - } - sb.Append(" ").AppendLine(); - - // Write out the keywords - if (keywordTab != null) - { - sb.Append(" ").AppendLine(); - var sortedKeywords = new List(keywordTab.Keys); - sortedKeywords.Sort(); - foreach (ulong keyword in sortedKeywords) - { - sb.Append(" ").AppendLine(); - } - sb.Append(" ").AppendLine(); - } - - sb.Append(" ").AppendLine(); - sb.Append(events); - sb.Append(" ").AppendLine(); - - if (templates.Length > 0) - { - sb.Append(" ").AppendLine(); - sb.Append(templates); - sb.Append(" ").AppendLine(); - } - sb.Append("").AppendLine(); - sb.Append("").AppendLine(); - sb.Append("").AppendLine(); - - // Output the localization information. - sb.Append("").AppendLine(); - - // - sb.Append(" ").AppendLine(); - sb.Append(" ").AppendLine(); - - var sortedStrings = new string[stringTab.Keys.Count]; - stringTab.Keys.CopyTo(sortedStrings, 0); - // Avoid using public Array.Sort as that attempts to access BinaryCompatibility. Unfortunately FrameworkEventSource gets called - // very early in the app domain creation, when _FusionStore is not set up yet, resulting in a failure to run the static constructory - // for BinaryCompatibility. This failure is then cached and a TypeInitializationException is thrown every time some code attampts to - // access BinaryCompatibility. - ArraySortHelper.IntrospectiveSort(sortedStrings, 0, sortedStrings.Length, Comparer.Default); - foreach (var stringKey in sortedStrings) - sb.Append(" ").AppendLine(); - sb.Append(" ").AppendLine(); - sb.Append(" ").AppendLine(); - sb.Append("").AppendLine(); - sb.AppendLine(""); - return sb.ToString(); - } - - #region private - private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elementName, string name) - { - stringBuilder.Append(" name=\"").Append(name).Append("\" "); - WriteMessageAttrib(sb, elementName, name, name); - } - private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string value) - { - string key = elementName + "_" + name; - // See if the user wants things localized. - if (resources != null) - { - string localizedString = resources.GetString(key); - if (localizedString != null) - value = localizedString; - } - if (value == null) - return; - if (elementName == "event") - value = TranslateToManifestConvention(value); - - stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\""); - stringTab.Add(key, value); - } - - private static string GetLevelName(EventLevel level) - { - return (((int)level >= 16) ? "" : "win:") + level.ToString(); - } - -#if FEATURE_MANAGED_ETW_CHANNELS - private string GetChannelName(EventChannel channel, string eventName) - { - ChannelInfo info = null; - if (channelTab == null || !channelTab.TryGetValue((int)channel, out info)) - throw new ArgumentException(Environment.GetResourceString("EventSource_UndefinedChannel", channel, eventName)); - return info.Name; - } -#endif - private string GetTaskName(EventTask task, string eventName) - { - if (task == EventTask.None) - return ""; - - string ret; - if (taskTab == null) - taskTab = new Dictionary(); - if (!taskTab.TryGetValue((int)task, out ret)) - ret = taskTab[(int)task] = eventName; - return ret; - } - private string GetOpcodeName(EventOpcode opcode, string eventName) - { - switch (opcode) - { - case EventOpcode.Info: - return "win:Info"; - case EventOpcode.Start: - return "win:Start"; - case EventOpcode.Stop: - return "win:Stop"; - case EventOpcode.DataCollectionStart: - return "win:DC_Start"; - case EventOpcode.DataCollectionStop: - return "win:DC_Stop"; - case EventOpcode.Extension: - return "win:Extension"; - case EventOpcode.Reply: - return "win:Reply"; - case EventOpcode.Resume: - return "win:Resume"; - case EventOpcode.Suspend: - return "win:Suspend"; - case EventOpcode.Send: - return "win:Send"; - case EventOpcode.Receive: - return "win:Receive"; - } - - string ret; - if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret)) - throw new ArgumentException(Environment.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName)); - return ret; - } - private string GetKeywords(ulong keywords, string eventName) - { - string ret = ""; - for (ulong bit = 1; bit != 0; bit <<= 1) - { - if ((keywords & bit) != 0) - { - string keyword; - if (keywordTab == null || !keywordTab.TryGetValue(bit, out keyword)) - throw new ArgumentException(Environment.GetResourceString("EventSource_UndefinedKeyword", bit.ToString("x", CultureInfo.CurrentCulture), eventName)); - if (ret.Length != 0) - ret = ret + " "; - ret = ret + keyword; - } - } - return ret; - } - private static string GetTypeName(Type type) - { - if (type.IsEnum) - { - FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - var typeName = GetTypeName(fields[0].FieldType); - return typeName.Replace("win:Int", "win:UInt"); // ETW requires enums to be unsigned. - } - switch (Type.GetTypeCode(type)) - { - case TypeCode.Boolean: - return "win:Boolean"; - case TypeCode.Byte: - return "win:UInt8"; - case TypeCode.UInt16: - return "win:UInt16"; - case TypeCode.UInt32: - return "win:UInt32"; - case TypeCode.UInt64: - return "win:UInt64"; - case TypeCode.SByte: - return "win:Int8"; - case TypeCode.Int16: - return "win:Int16"; - case TypeCode.Int32: - return "win:Int32"; - case TypeCode.Int64: - return "win:Int64"; - case TypeCode.String: - return "win:UnicodeString"; - case TypeCode.Single: - return "win:Float"; - case TypeCode.Double: - return "win:Double"; - case TypeCode.DateTime: - return "win:FILETIME"; - default: - if (type == typeof(Guid)) - return "win:GUID"; - throw new ArgumentException(Environment.GetResourceString("EventSource_UnsupportedEventTypeInManifest", type.Name)); - } - } - - // Manifest messages use %N conventions for their message substitutions. Translate from - // .NET conventions. We can't use RegEx for this (we are in mscorlib), so we do it 'by hand' - private static string TranslateToManifestConvention(string eventMessage) - { - StringBuilder stringBuilder = null; // We lazily create this - int writtenSoFar = 0; - int chIdx = -1; - for (int i = 0; ; ) - { - if (i >= eventMessage.Length) - { - if (stringBuilder == null) - return eventMessage; - stringBuilder.Append(eventMessage, writtenSoFar, i - writtenSoFar); - return stringBuilder.ToString(); - } - if (eventMessage[i] == '{') - { - int leftBracket = i; - i++; - int argNum = 0; - while (i < eventMessage.Length && Char.IsDigit(eventMessage[i])) - { - argNum = argNum * 10 + eventMessage[i] - '0'; - i++; - } - if (i < eventMessage.Length && eventMessage[i] == '}') - { - i++; - if (stringBuilder == null) - stringBuilder = new StringBuilder(); - stringBuilder.Append(eventMessage, writtenSoFar, leftBracket - writtenSoFar); - stringBuilder.Append('%').Append(argNum + 1); - writtenSoFar = i; - } - } - else if ((chIdx = "&<>'\"".IndexOf(eventMessage[i])) >= 0) - { - string[] xmlEscapes = {"&", "<", ">", "'", """}; - var update = new Action( - (ch, escape) => { - if (stringBuilder == null) - stringBuilder = new StringBuilder(); - stringBuilder.Append(eventMessage, writtenSoFar, i - writtenSoFar); - i++; - stringBuilder.Append(escape); - writtenSoFar = i; - }); - update(eventMessage[i], xmlEscapes[chIdx]); - } - else - i++; - } - } - -#if FEATURE_MANAGED_ETW_CHANNELS - class ChannelInfo - { - public string Name; - public ChannelAttribute Attribs; - } -#endif - - Dictionary opcodeTab; - Dictionary taskTab; -#if FEATURE_MANAGED_ETW_CHANNELS - Dictionary channelTab; -#endif - Dictionary keywordTab; - Dictionary mapsTab; - - Dictionary stringTab; // Maps unlocalized strings to localized ones - - StringBuilder sb; // Holds the provider information. - StringBuilder events; // Holds the events. - StringBuilder templates; - -#if FEATURE_MANAGED_ETW_CHANNELS - string providerName; -#endif - ResourceManager resources; // Look up localized strings here. - - // State we track between StartEvent and EndEvent. - string templateName; // Every event gets its own template (eventName + "Args") this hold it. - int numParams; // keeps track of the number of args the event has. - #endregion - } - - /// - /// Used to send the m_rawManifest into the event dispatcher as a series of events. - /// - internal struct ManifestEnvelope - { - public const int MaxChunkSize = 0xFF00; - public enum ManifestFormats : byte - { - SimpleXmlFormat = 1, // simply dump the XML manifest as UTF8 - } - - public ManifestFormats Format; - public byte MajorVersion; - public byte MinorVersion; - public byte Magic; - public ushort TotalChunks; - public ushort ChunkNumber; - }; - - #endregion -} - diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/stackframe.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/stackframe.cs index f88aad8d449..4e6c63ebfaf 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/stackframe.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/stackframe.cs @@ -323,25 +323,26 @@ namespace System.Diagnostics { private void BuildStackFrame(int skipFrames, bool fNeedFileInfo) { - StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, null); - - StackTrace.GetStackFramesInternal (StackF, 0, null); - - int iNumOfFrames = StackF.GetNumberOfFrames(); - - skipFrames += StackTrace.CalculateFramesToSkip (StackF, iNumOfFrames); - - if ((iNumOfFrames - skipFrames) > 0) + using (StackFrameHelper StackF = new StackFrameHelper(null)) { - method = StackF.GetMethodBase (skipFrames); - offset = StackF.GetOffset (skipFrames); - ILOffset = StackF.GetILOffset (skipFrames); - if (fNeedFileInfo) + StackF.InitializeSourceInfo(0, fNeedFileInfo, null); + + int iNumOfFrames = StackF.GetNumberOfFrames(); + + skipFrames += StackTrace.CalculateFramesToSkip(StackF, iNumOfFrames); + + if ((iNumOfFrames - skipFrames) > 0) { - strFileName = StackF.GetFilename (skipFrames); - iLineNumber = StackF.GetLineNumber (skipFrames); - iColumnNumber = StackF.GetColumnNumber (skipFrames); - } + method = StackF.GetMethodBase(skipFrames); + offset = StackF.GetOffset(skipFrames); + ILOffset = StackF.GetILOffset(skipFrames); + if (fNeedFileInfo) + { + strFileName = StackF.GetFilename(skipFrames); + iLineNumber = StackF.GetLineNumber(skipFrames); + iColumnNumber = StackF.GetColumnNumber(skipFrames); + } + } } } } diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/stacktrace.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/stacktrace.cs index d7fd9727a00..bf471ff5515 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/stacktrace.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/stacktrace.cs @@ -23,7 +23,7 @@ namespace System.Diagnostics { // to the unmanaged definition of the StackFrameHelper class, in // VM\DebugDebugger.h. The binder will catch some of these layout problems. [Serializable] - internal class StackFrameHelper + internal class StackFrameHelper : IDisposable { [NonSerialized] private Thread targetThread; @@ -32,14 +32,20 @@ namespace System.Diagnostics { // this field is here only for backwards compatibility of serialization format private MethodBase[] rgMethodBase; -#pragma warning disable 414 // Field is not used from managed. +#pragma warning disable 414 // dynamicMethods is an array of System.Resolver objects, used to keep // DynamicMethodDescs alive for the lifetime of StackFrameHelper. - private Object dynamicMethods; -#pragma warning restore 414 + private Object dynamicMethods; // Field is not used from managed. [NonSerialized] private IntPtr[] rgMethodHandle; + private String[] rgAssemblyPath; + private IntPtr[] rgLoadedPeAddress; + private int[] rgiLoadedPeSize; + private IntPtr[] rgInMemoryPdbAddress; + private int[] rgiInMemoryPdbSize; + // if rgiMethodToken[i] == 0, then don't attempt to get the portable PDB source/info + private int[] rgiMethodToken; private String[] rgFilename; private int[] rgiLineNumber; private int[] rgiColumnNumber; @@ -47,21 +53,38 @@ namespace System.Diagnostics { [OptionalField] private bool[] rgiLastFrameFromForeignExceptionStackTrace; #endif // FEATURE_EXCEPTIONDISPATCHINFO + private GetSourceLineInfoDelegate getSourceLineInfo; private int iFrameCount; - private bool fNeedFileInfo; +#pragma warning restore 414 + + private delegate void GetSourceLineInfoDelegate(string assemblyPath, IntPtr loadedPeAddress, int loadedPeSize, + IntPtr inMemoryPdbAddress, int inMemoryPdbSize, int methodToken, int ilOffset, + out string sourceFile, out int sourceLine, out int sourceColumn); + + private static Type s_symbolsType = null; + private static MethodInfo s_symbolsMethodInfo = null; + [ThreadStatic] + private static int t_reentrancy = 0; - public StackFrameHelper(bool fNeedFileLineColInfo, Thread target) + public StackFrameHelper(Thread target) { targetThread = target; rgMethodBase = null; rgMethodHandle = null; + rgiMethodToken = null; rgiOffset = null; rgiILOffset = null; + rgAssemblyPath = null; + rgLoadedPeAddress = null; + rgiLoadedPeSize = null; + rgInMemoryPdbAddress = null; + rgiInMemoryPdbSize = null; + dynamicMethods = null; rgFilename = null; rgiLineNumber = null; rgiColumnNumber = null; - dynamicMethods = null; + getSourceLineInfo = null; #if FEATURE_EXCEPTIONDISPATCHINFO rgiLastFrameFromForeignExceptionStackTrace = null; @@ -75,10 +98,99 @@ namespace System.Diagnostics { // limit in the future, then we should expose it in the managed API so applications can // override it. iFrameCount = 0; + } + + // + // Initializes the stack trace helper. If fNeedFileInfo is true, initializes rgFilename, + // rgiLineNumber and rgiColumnNumber fields using the portable PDB reader if not already + // done by GetStackFramesInternal (on Windows for old PDB format). + // + [SecuritySafeCritical] + internal void InitializeSourceInfo(int iSkip, bool fNeedFileInfo, Exception exception) + { + StackTrace.GetStackFramesInternal(this, iSkip, fNeedFileInfo, exception); + if (!fNeedFileInfo) + return; + + // Check if this function is being reentered because of an exception in the code below + if (t_reentrancy > 0) + return; + + t_reentrancy++; + try + { + // need private reflection below + new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert(); + + if (s_symbolsMethodInfo == null) + { + s_symbolsType = Type.GetType( + "System.Diagnostics.StackTraceSymbols, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + throwOnError: false); + + if (s_symbolsType == null) + { + return; + } + + s_symbolsMethodInfo = s_symbolsType.GetMethod("GetSourceLineInfo", + new Type[] { typeof(string), + typeof(IntPtr), + typeof(int), + typeof(IntPtr), + typeof(int), + typeof(int), + typeof(int), + typeof(string).MakeByRefType(), + typeof(int).MakeByRefType(), + typeof(int).MakeByRefType() }); + if (s_symbolsMethodInfo == null) + return; + } + + if (getSourceLineInfo == null) + { + // Create an instance of System.Diagnostics.Stacktrace.Symbols + object target = Activator.CreateInstance(s_symbolsType); + + // Create an instance delegate for the GetSourceLineInfo method + getSourceLineInfo = (GetSourceLineInfoDelegate)s_symbolsMethodInfo.CreateDelegate(typeof(GetSourceLineInfoDelegate), target); + } + + for (int index = 0; index < iFrameCount; index++) + { + // If there was some reason not to try get get the symbols from the portable PDB reader like the module was + // ENC or the source/line info was already retrieved, the method token is 0. + if (rgiMethodToken[index] != 0) + { + getSourceLineInfo(rgAssemblyPath[index], rgLoadedPeAddress[index], rgiLoadedPeSize[index], + rgInMemoryPdbAddress[index], rgiInMemoryPdbSize[index], rgiMethodToken[index], + rgiILOffset[index], out rgFilename[index], out rgiLineNumber[index], out rgiColumnNumber[index]); + } + } + } + catch + { + } + finally + { + t_reentrancy--; + } + } + - fNeedFileInfo = fNeedFileLineColInfo; + void IDisposable.Dispose() + { + if (getSourceLineInfo != null) + { + IDisposable disposable = getSourceLineInfo.Target as IDisposable; + if (disposable != null) + { + disposable.Dispose(); + } + } } - + [System.Security.SecuritySafeCritical] public virtual MethodBase GetMethodBase(int i) { @@ -99,9 +211,9 @@ namespace System.Diagnostics { public virtual int GetOffset(int i) { return rgiOffset[i];} public virtual int GetILOffset(int i) { return rgiILOffset[i];} - public virtual String GetFilename(int i) { return rgFilename[i];} - public virtual int GetLineNumber(int i) { return rgiLineNumber[i];} - public virtual int GetColumnNumber(int i) { return rgiColumnNumber[i];} + public virtual String GetFilename(int i) { return rgFilename == null ? null : rgFilename[i];} + public virtual int GetLineNumber(int i) { return rgiLineNumber == null ? 0 : rgiLineNumber[i];} + public virtual int GetColumnNumber(int i) { return rgiColumnNumber == null ? 0 : rgiColumnNumber[i];} #if FEATURE_EXCEPTIONDISPATCHINFO public virtual bool IsLastFrameFromForeignExceptionStackTrace(int i) @@ -344,11 +456,10 @@ namespace System.Diagnostics { [System.Security.SecuritySafeCritical] [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, Exception e); + internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, bool fNeedFileInfo, Exception e); internal static int CalculateFramesToSkip(StackFrameHelper StackF, int iNumFrames) { - int iRetVal = 0; String PackageName = "System.Diagnostics"; @@ -378,63 +489,63 @@ namespace System.Diagnostics { // Retrieves an object with stack trace information encoded. // It leaves out the first "iSkip" lines of the stacktrace. // - private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, - Exception e) + private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, Exception e) { m_iMethodsToSkip += iSkip; - - StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread); - - GetStackFramesInternal(StackF, 0, e); - - m_iNumOfFrames = StackF.GetNumberOfFrames(); - - if (m_iMethodsToSkip > m_iNumOfFrames) - m_iMethodsToSkip = m_iNumOfFrames; - if (m_iNumOfFrames != 0) + using (StackFrameHelper StackF = new StackFrameHelper(targetThread)) { - frames = new StackFrame[m_iNumOfFrames]; + StackF.InitializeSourceInfo(0, fNeedFileInfo, e); + + m_iNumOfFrames = StackF.GetNumberOfFrames(); + + if (m_iMethodsToSkip > m_iNumOfFrames) + m_iMethodsToSkip = m_iNumOfFrames; - for (int i = 0; i < m_iNumOfFrames; i++) + if (m_iNumOfFrames != 0) { - bool fDummy1 = true; - bool fDummy2 = true; - StackFrame sfTemp = new StackFrame(fDummy1, fDummy2); + frames = new StackFrame[m_iNumOfFrames]; - sfTemp.SetMethodBase(StackF.GetMethodBase(i)); - sfTemp.SetOffset(StackF.GetOffset(i)); - sfTemp.SetILOffset(StackF.GetILOffset(i)); + for (int i = 0; i < m_iNumOfFrames; i++) + { + bool fDummy1 = true; + bool fDummy2 = true; + StackFrame sfTemp = new StackFrame(fDummy1, fDummy2); + + sfTemp.SetMethodBase(StackF.GetMethodBase(i)); + sfTemp.SetOffset(StackF.GetOffset(i)); + sfTemp.SetILOffset(StackF.GetILOffset(i)); #if FEATURE_EXCEPTIONDISPATCHINFO sfTemp.SetIsLastFrameFromForeignExceptionStackTrace(StackF.IsLastFrameFromForeignExceptionStackTrace(i)); #endif // FEATURE_EXCEPTIONDISPATCHINFO - if (fNeedFileInfo) - { - sfTemp.SetFileName(StackF.GetFilename (i)); - sfTemp.SetLineNumber(StackF.GetLineNumber(i)); - sfTemp.SetColumnNumber(StackF.GetColumnNumber(i)); - } + if (fNeedFileInfo) + { + sfTemp.SetFileName(StackF.GetFilename(i)); + sfTemp.SetLineNumber(StackF.GetLineNumber(i)); + sfTemp.SetColumnNumber(StackF.GetColumnNumber(i)); + } - frames[i] = sfTemp; - } + frames[i] = sfTemp; + } - // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace, - // but this is not desired if building a stack trace from an exception. - if (e == null) - m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames); + // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace, + // but this is not desired if building a stack trace from an exception. + if (e == null) + m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames); - m_iNumOfFrames -= m_iMethodsToSkip; - if (m_iNumOfFrames < 0) - { - m_iNumOfFrames = 0; - } - } + m_iNumOfFrames -= m_iMethodsToSkip; + if (m_iNumOfFrames < 0) + { + m_iNumOfFrames = 0; + } + } - // In case this is the same object being re-used, set frames to null - else - frames = null; + // In case this is the same object being re-used, set frames to null + else + frames = null; + } } // Property to get the number of frames in the stack trace diff --git a/mcs/class/referencesource/mscorlib/system/globalization/cultureinfo.cs b/mcs/class/referencesource/mscorlib/system/globalization/cultureinfo.cs index b3cf1c0cb2e..12f7d6bbf95 100644 --- a/mcs/class/referencesource/mscorlib/system/globalization/cultureinfo.cs +++ b/mcs/class/referencesource/mscorlib/system/globalization/cultureinfo.cs @@ -358,6 +358,25 @@ namespace System.Globalization { this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo)); } + private CultureInfo(CultureData cultureData) + { + Contract.Assert(cultureData != null); + m_cultureData = cultureData; + m_name = cultureData.CultureName; + m_isInherited = false; + } + + private static CultureInfo CreateCultureInfoNoThrow(string name, bool useUserOverride) + { + Contract.Assert(name != null); + CultureData cultureData = CultureData.GetCultureData(name, useUserOverride); + if (cultureData == null) + { + return null; + } + + return new CultureInfo(cultureData); + } #if FEATURE_USE_LCID public CultureInfo(int culture) : this(culture, true) { @@ -958,29 +977,29 @@ namespace System.Globalization { get { Contract.Ensures(Contract.Result() != null); + CultureInfo culture = null; if (null == m_parent) { - try - { - string parentName = this.m_cultureData.SPARENT; + string parentName = this.m_cultureData.SPARENT; - if (String.IsNullOrEmpty(parentName)) - { - m_parent = InvariantCulture; - } - else - { - m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride); - } + if (String.IsNullOrEmpty(parentName)) + { + culture = InvariantCulture; } - catch (ArgumentException) + else { - // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant - // We can't allow ourselves to fail. In case of custom cultures the parent of the - // current custom culture isn't installed. - m_parent = InvariantCulture; + culture = CreateCultureInfoNoThrow(parentName, m_cultureData.UseUserOverride); + if (culture == null) + { + // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant + // We can't allow ourselves to fail. In case of custom cultures the parent of the + // current custom culture isn't installed. + culture = InvariantCulture; + } } + + Interlocked.CompareExchange(ref m_parent, culture, null); } return m_parent; } diff --git a/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs b/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs index 6ba1a392982..e0027b5b6d0 100644 --- a/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs +++ b/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs @@ -22,7 +22,6 @@ namespace System.Globalization { ** Taiwan 01/01/01 8088/12/31 ============================================================================*/ - [System.Runtime.InteropServices.ComVisible(true)] [Serializable] public class TaiwanCalendar: Calendar { // diff --git a/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/ipropertyvaluefactory.cs b/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/ipropertyvaluefactory.cs deleted file mode 100644 index 8947ac5356f..00000000000 --- a/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/ipropertyvaluefactory.cs +++ /dev/null @@ -1,60 +0,0 @@ -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== -// -// [....] -// [....] -// [....] - -using System; - -namespace System.Runtime.InteropServices.WindowsRuntime -{ - [ComImport] - [Guid("629bdbc8-d932-4ff4-96b9-8d96c5c1e858")] - [WindowsRuntimeImport] - internal interface IPropertyValueFactory - { - IPropertyValue CreateEmpty(); - IPropertyValue CreateUInt8(byte value); - IPropertyValue CreateInt16(short value); - IPropertyValue CreateUInt16(ushort value); - IPropertyValue CreateInt32(int value); - IPropertyValue CreateUInt32(uint value); - IPropertyValue CreateInt64(long value); - IPropertyValue CreateUInt64(ulong value); - IPropertyValue CreateSingle(float value); - IPropertyValue CreateDouble(double value); - IPropertyValue CreateChar16(char value); - IPropertyValue CreateBoolean(bool value); - IPropertyValue CreateString(string value); - IPropertyValue CreateInspectable(object value); - IPropertyValue CreateGuid(Guid value); - IPropertyValue CreateDateTime(DateTimeOffset value); - IPropertyValue CreateTimeSpan(TimeSpan value); - IPropertyValue CreatePoint(Point value); - IPropertyValue CreateSize(Size value); - IPropertyValue CreateRect(Rect value); - IPropertyValue CreateUInt8Array(byte[] value); - IPropertyValue CreateInt16Array(short[] value); - IPropertyValue CreateUInt16Array(ushort[] value); - IPropertyValue CreateInt32Array(Int32[] value); - IPropertyValue CreateUInt32Array(UInt32[] value); - IPropertyValue CreateInt64Array(Int64[] value); - IPropertyValue CreateUInt64Array(UInt64[] value); - IPropertyValue CreateSingleArray(Single[] value); - IPropertyValue CreateDoubleArray(Double[] value); - IPropertyValue CreateChar16Array(Char[] value); - IPropertyValue CreateBooleanArray(Boolean[] value); - IPropertyValue CreateStringArray(String[] value); - IPropertyValue CreateInspectableArray(Object[] value); - IPropertyValue CreateGuidArray(Guid[] value); - IPropertyValue CreateDateTimeArray(DateTimeOffset[] value); - IPropertyValue CreateTimeSpanArray(TimeSpan[] value); - IPropertyValue CreatePointArray(Point[] value); - IPropertyValue CreateSizeArray(Size[] value); - IPropertyValue CreateRectArray(Rect[] value); - } -} diff --git a/mcs/class/referencesource/mscorlib/system/stringcomparer.cs b/mcs/class/referencesource/mscorlib/system/stringcomparer.cs index fd49f74502d..0de343b1a04 100644 --- a/mcs/class/referencesource/mscorlib/system/stringcomparer.cs +++ b/mcs/class/referencesource/mscorlib/system/stringcomparer.cs @@ -133,31 +133,46 @@ namespace System { , IWellKnownStringEqualityComparer #endif { + private CompareInfo _compareInfo; private bool _ignoreCase; + [OptionalField] + private CompareOptions _options; internal CultureAwareComparer(CultureInfo culture, bool ignoreCase) { _compareInfo = culture.CompareInfo; _ignoreCase = ignoreCase; + _options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; } internal CultureAwareComparer(CompareInfo compareInfo, bool ignoreCase) { _compareInfo = compareInfo; _ignoreCase = ignoreCase; + _options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; + } + + internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options) { + _compareInfo = compareInfo; + _options = options; + + // set the _ignoreCase flag to preserve compat in case this type is serialized on a + // newer version of the framework and deserialized on an older version of the framework + _ignoreCase = ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase || + (options & CompareOptions.OrdinalIgnoreCase ) == CompareOptions.OrdinalIgnoreCase); } public override int Compare(string x, string y) { if (Object.ReferenceEquals(x, y)) return 0; if (x == null) return -1; if (y == null) return 1; - return _compareInfo.Compare(x, y, _ignoreCase? CompareOptions.IgnoreCase : CompareOptions.None); + return _compareInfo.Compare(x, y, _options); } public override bool Equals(string x, string y) { if (Object.ReferenceEquals(x ,y)) return true; if (x == null || y == null) return false; - return (_compareInfo.Compare(x, y, _ignoreCase? CompareOptions.IgnoreCase : CompareOptions.None) == 0); + return (_compareInfo.Compare(x, y, _options) == 0); } public override int GetHashCode(string obj) { @@ -166,13 +181,7 @@ namespace System { } Contract.EndContractBlock(); - CompareOptions options = CompareOptions.None; - - if( _ignoreCase) { - options |= CompareOptions.IgnoreCase; - } - - return _compareInfo.GetHashCodeOfString(obj, options); + return _compareInfo.GetHashCodeOfString(obj, _options); } // Equals method for the comparer itself. @@ -181,7 +190,8 @@ namespace System { if( comparer == null) { return false; } - return (this._ignoreCase == comparer._ignoreCase) && (this._compareInfo.Equals(comparer._compareInfo)); + return (this._ignoreCase == comparer._ignoreCase) && (this._compareInfo.Equals(comparer._compareInfo) + && this._options == comparer._options); } public override int GetHashCode() { diff --git a/mcs/class/referencesource/mscorlib/system/threading/Tasks/ParallelRangeManager.cs b/mcs/class/referencesource/mscorlib/system/threading/Tasks/ParallelRangeManager.cs index 7c625cf2292..9f2509f3ee9 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/Tasks/ParallelRangeManager.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/Tasks/ParallelRangeManager.cs @@ -16,6 +16,7 @@ using System; using System.Threading; using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; #pragma warning disable 0420 @@ -24,6 +25,7 @@ namespace System.Threading.Tasks /// /// Represents an index range /// + [StructLayout(LayoutKind.Auto)] internal struct IndexRange { // the From and To values for this range. These do not change. @@ -32,7 +34,11 @@ namespace System.Threading.Tasks // The shared index, stored as the offset from nFromInclusive. Using an offset rather than the actual // value saves us from overflows that can happen due to multiple workers racing to increment this. - // All updates to this field need to be interlocked. + // All updates to this field need to be interlocked. To avoid split interlockeds across cache-lines + // in 32-bit processes, in 32-bit processes when the range fits in a 32-bit value, we prefer to use + // a 32-bit field, and just use the first 32-bits of the long. And to minimize false sharing, each + // value is stored in its own heap-allocated object, which is lazily allocated by the thread using + // that range, minimizing the chances it'll be near the objects from other threads. internal volatile Shared m_nSharedCurrentIndexOffset; // to be set to 1 by the worker that finishes this range. It's OK to do a non-interlocked write here. @@ -43,6 +49,7 @@ namespace System.Threading.Tasks /// /// The RangeWorker struct wraps the state needed by a task that services the parallel loop /// + [StructLayout(LayoutKind.Auto)] internal struct RangeWorker { // reference to the IndexRange array allocated by the range manager @@ -61,13 +68,17 @@ namespace System.Threading.Tasks // the increment value is doubled each time this worker finds work, and is capped at this value internal readonly long m_nMaxIncrementValue; + // whether to use 32-bits or 64-bits of current index in each range + internal readonly bool _use32BitCurrentIndex; + /// /// Initializes a RangeWorker struct /// - internal RangeWorker(IndexRange[] ranges, int nInitialRange, long nStep) + internal RangeWorker(IndexRange[] ranges, int nInitialRange, long nStep, bool use32BitCurrentIndex) { m_indexRanges = ranges; m_nCurrentIndexRange = nInitialRange; + _use32BitCurrentIndex = use32BitCurrentIndex; m_nStep = nStep; m_nIncrementValue = nStep; @@ -104,8 +115,24 @@ namespace System.Threading.Tasks } // this access needs to be on the array slot - long nMyOffset = Interlocked.Add(ref m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset.Value, - m_nIncrementValue) - m_nIncrementValue; + long nMyOffset; + if (IntPtr.Size == 4 && _use32BitCurrentIndex) + { + // In 32-bit processes, we prefer to use 32-bit interlocked operations, to avoid the possibility of doing + // a 64-bit interlocked when the target value crosses a cache line, as that can be super expensive. + // We use the first 32 bits of the Int64 index in such cases. + unsafe + { + fixed (long* indexPtr = &m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset.Value) + { + nMyOffset = Interlocked.Add(ref *(int*)indexPtr, (int)m_nIncrementValue) - m_nIncrementValue; + } + } + } + else + { + nMyOffset = Interlocked.Add(ref m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset.Value, m_nIncrementValue) - m_nIncrementValue; + } if (currentRange.m_nToExclusive - currentRange.m_nFromInclusive > nMyOffset) { @@ -187,6 +214,7 @@ namespace System.Threading.Tasks internal class RangeManager { internal readonly IndexRange[] m_indexRanges; + internal readonly bool _use32BitCurrentIndex; internal int m_nCurrentIndexRangeToAssign; internal long m_nStep; @@ -234,6 +262,7 @@ namespace System.Threading.Tasks // Convert to signed so the rest of the logic works. // Should be fine so long as uRangeSize < Int64.MaxValue, which we guaranteed by setting #workers >= 2. long nRangeSize = (long)uRangeSize; + _use32BitCurrentIndex = IntPtr.Size == 4 && nRangeSize <= int.MaxValue; // allocate the array of index ranges m_indexRanges = new IndexRange[nNumRanges]; @@ -274,7 +303,7 @@ namespace System.Threading.Tasks int nInitialRange = (Interlocked.Increment(ref m_nCurrentIndexRangeToAssign) - 1) % m_indexRanges.Length; - return new RangeWorker(m_indexRanges, nInitialRange, m_nStep); + return new RangeWorker(m_indexRanges, nInitialRange, m_nStep, _use32BitCurrentIndex); } } } diff --git a/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskFactory.cs b/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskFactory.cs index b15df277ab4..de78cb0b182 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskFactory.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/Tasks/TaskFactory.cs @@ -2502,7 +2502,23 @@ namespace System.Threading.Tasks checkArgsOnly = true; } // Otherwise, add the completion action and keep going. - else task.AddCompletionAction(promise); + else + { + task.AddCompletionAction(promise); + if (promise.IsCompleted) + { + // One of the previous tasks that already had its continuation registered may have + // raced to complete with our adding the continuation to this task. The completion + // routine would have gone through and removed the continuation from all of the tasks + // with which it was already registered, but if the ---- causes this continuation to + // be added after that, it'll never be removed. As such, after adding the continuation, + // we check to see whether the promise has already completed, and if it has, we try to + // manually remove the continuation from this task. If it was already removed, it'll be + // a nop, and if we ---- to remove it, the synchronization in RemoveContinuation will + // keep things consistent. + task.RemoveContinuation(promise); + } + } } return promise; diff --git a/mcs/class/referencesource/mscorlib/system/tuple.cs b/mcs/class/referencesource/mscorlib/system/tuple.cs index 225cfe0890e..b42f1107907 100644 --- a/mcs/class/referencesource/mscorlib/system/tuple.cs +++ b/mcs/class/referencesource/mscorlib/system/tuple.cs @@ -3,17 +3,16 @@ using System.Text; using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; namespace System { /// /// Helper so we can call some tuple methods recursively without knowing the underlying types. /// - internal interface ITuple { + internal interface ITupleInternal : ITuple { string ToString(StringBuilder sb); int GetHashCode(IEqualityComparer comparer); - int Size { get; } - } public static class Tuple { @@ -50,7 +49,8 @@ namespace System { } // From System.Web.Util.HashCodeCombiner - internal static int CombineHashCodes(int h1, int h2) { + internal static int CombineHashCodes(int h1, int h2) + { return (((h1 << 5) + h1) ^ h2); } @@ -80,7 +80,7 @@ namespace System { } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; @@ -130,30 +130,44 @@ namespace System { return comparer.GetHashCode(m_Item1); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(")"); return sb.ToString(); } - int ITuple.Size { - get { - return 1; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 1; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + if (index != 0) + { + throw new IndexOutOfRangeException(); + } + return Item1; } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -212,16 +226,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -229,15 +243,33 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 2; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 2; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -303,16 +335,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -322,15 +354,35 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 3; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 3; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -403,16 +455,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -424,15 +476,37 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 4; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 4; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -512,16 +586,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -535,15 +609,39 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 5; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 5; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -630,16 +728,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -655,15 +753,41 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 6; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 6; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -757,16 +881,16 @@ namespace System { return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7)); } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -784,15 +908,43 @@ namespace System { return sb.ToString(); } - int ITuple.Size { - get { - return 7; + /// + /// The number of positions in this data structure. + /// + int ITuple.Length => 7; + + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + case 6: + return Item7; + default: + throw new IndexOutOfRangeException(); + } } } } [Serializable] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple { + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple { private readonly T1 m_Item1; private readonly T2 m_Item2; @@ -813,7 +965,7 @@ namespace System { public TRest Rest { get { return m_Rest; } } public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { - if (!(rest is ITuple)) { + if (!(rest is ITupleInternal)) { throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleLastArgumentNotATuple")); } @@ -895,11 +1047,11 @@ namespace System { Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - ITuple t = (ITuple) m_Rest; - if(t.Size >= 8) { return t.GetHashCode(comparer); } + ITupleInternal t = (ITupleInternal) m_Rest; + if(t.Length >= 8) { return t.GetHashCode(comparer); } // In this case, the rest memeber has less than 8 elements so we need to combine some our elements with the elements in rest - int k = 8 - t.Size; + int k = 8 - t.Length; switch(k) { case 1: return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item7), t.GetHashCode(comparer)); @@ -920,16 +1072,16 @@ namespace System { return -1; } - Int32 ITuple.GetHashCode(IEqualityComparer comparer) { + Int32 ITupleInternal.GetHashCode(IEqualityComparer comparer) { return ((IStructuralEquatable) this).GetHashCode(comparer); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("("); - return ((ITuple)this).ToString(sb); + return ((ITupleInternal)this).ToString(sb); } - string ITuple.ToString(StringBuilder sb) { + string ITupleInternal.ToString(StringBuilder sb) { sb.Append(m_Item1); sb.Append(", "); sb.Append(m_Item2); @@ -944,12 +1096,46 @@ namespace System { sb.Append(", "); sb.Append(m_Item7); sb.Append(", "); - return ((ITuple)m_Rest).ToString(sb); + return ((ITupleInternal)m_Rest).ToString(sb); + } + + /// + /// The number of positions in this data structure. + /// + int ITuple.Length + { + get + { + return 7 + ((ITupleInternal)Rest).Length; + } } - int ITuple.Size { - get { - return 7 + ((ITuple)m_Rest).Size; + /// + /// Get the element at position . + /// + object ITuple.this[int index] + { + get + { + switch (index) + { + case 0: + return Item1; + case 1: + return Item2; + case 2: + return Item3; + case 3: + return Item4; + case 4: + return Item5; + case 5: + return Item6; + case 6: + return Item7; + } + + return ((ITupleInternal)Rest)[index - 7]; } } } -- 2.11.4.GIT