From d29ebf3f4dd8c599d0cd6e191234186689254355 Mon Sep 17 00:00:00 2001 From: pumpkin-bit Date: Fri, 31 Jul 2026 17:57:15 +0500 Subject: [PATCH] Fix NullReferenceException in DbConnectionOptions.ConvertValueToBoolean --- .../Data/Common/DbConnectionOptions.Common.cs | 76 ++++++++++--------- .../Common/DbConnectionStringBuilderTest.cs | 11 +++ 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs b/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs index da10c9fe31f694..784b3ed24fdc35 100644 --- a/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs +++ b/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs @@ -114,14 +114,18 @@ private string UsersConnectionString(bool hidePassword, bool forceHidePassword) public bool ConvertValueToBoolean(string keyName, bool defaultValue) { string? value; - // TODO: Is it possible for _parsetable to contain a null value here? If so there's a bug here, investigate. return _parsetable.TryGetValue(keyName, out value) ? - ConvertValueToBooleanInternal(keyName, value!) : + ConvertValueToBooleanInternal(keyName, value) : defaultValue; } - internal static bool ConvertValueToBooleanInternal(string keyName, string stringValue) + internal static bool ConvertValueToBooleanInternal(string keyName, string? stringValue) { + if (stringValue is null) + { + throw ADP.InvalidConnectionOptionValue(keyName); + } + if (CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes")) return true; else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no")) @@ -344,7 +348,7 @@ internal static int GetKeyValuePair(string connectionString, int currentPosition } buffer.Append(currentChar); } - ParserExit: + ParserExit: switch (parserState) { case ParserState.Key: @@ -541,48 +545,48 @@ private static void ParseComparison(Dictionary parsetable, stri try { #endif - int nextStartPosition = 0; - int endPosition = connectionString.Length; - while (nextStartPosition < endPosition) - { - int startPosition = nextStartPosition; + int nextStartPosition = 0; + int endPosition = connectionString.Length; + while (nextStartPosition < endPosition) + { + int startPosition = nextStartPosition; - string? keyname, keyvalue; - nextStartPosition = GetKeyValuePair(connectionString, startPosition, buffer, firstKey, out keyname, out keyvalue); - if (string.IsNullOrEmpty(keyname)) - { - break; - } + string? keyname, keyvalue; + nextStartPosition = GetKeyValuePair(connectionString, startPosition, buffer, firstKey, out keyname, out keyvalue); + if (string.IsNullOrEmpty(keyname)) + { + break; + } #if DEBUG DebugTraceKeyValuePair(keyname, keyvalue, synonyms); Debug.Assert(IsKeyNameValid(keyname), "ParseFailure, invalid keyname"); Debug.Assert(IsValueValidInternal(keyvalue), "parse failure, invalid keyvalue"); #endif - string? synonym; - string? realkeyname = null != synonyms ? - (synonyms.TryGetValue(keyname, out synonym) ? synonym : null) : - keyname; + string? synonym; + string? realkeyname = null != synonyms ? + (synonyms.TryGetValue(keyname, out synonym) ? synonym : null) : + keyname; - if (!IsKeyNameValid(realkeyname)) - { - throw ADP.KeywordNotSupported(keyname); - } - if (!firstKey || !parsetable.ContainsKey(realkeyname)) - { - parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first) - } + if (!IsKeyNameValid(realkeyname)) + { + throw ADP.KeywordNotSupported(keyname); + } + if (!firstKey || !parsetable.ContainsKey(realkeyname)) + { + parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first) + } - if (null != localKeychain) - { - localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition); - } - else if (buildChain) - { - // first time only - don't contain modified chain from UDL file - keychain = localKeychain = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition); - } + if (null != localKeychain) + { + localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition); + } + else if (buildChain) + { + // first time only - don't contain modified chain from UDL file + keychain = localKeychain = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition); } + } #if DEBUG } catch (ArgumentException e) diff --git a/src/libraries/System.Data.Common/tests/System/Data/Common/DbConnectionStringBuilderTest.cs b/src/libraries/System.Data.Common/tests/System/Data/Common/DbConnectionStringBuilderTest.cs index 656c1b2c3d7698..d45b95d91c6ad5 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/Common/DbConnectionStringBuilderTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/Common/DbConnectionStringBuilderTest.cs @@ -69,6 +69,17 @@ public void Add() Assert.True(_builder.ContainsKey("Dsn")); } + [Fact] + public void ConnectionString_EmptyValue_ParsedAsEmptyString() + { + _builder.ConnectionString = "Persist Security Info="; + Assert.False(_builder.ContainsKey("Persist Security Info")); + + _builder.ConnectionString = "Persist Security Info=\"\""; + Assert.True(_builder.ContainsKey("Persist Security Info")); + Assert.Equal(string.Empty, _builder["Persist Security Info"]); + } + [Fact] public void Add_Keyword_Invalid() {