Brian has pointed out how some string comparison functions will perform an implicit uppercase when doing case-insensitive comparisons. Obviously this could open up security holes in applications performing input validation.
My quick analysis on this is – your software is safe unless I can control the culture tag. Recommendation perform input validation prior to doing string comparison, otherwise these test cases might catch you off guard:
// U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE will lowercase to i U+0049
Compare("\u0130", "i", ignoreCase);
// U+0131 LATIN SMALL LETTER DOTLESS I will uppercase to I U+0069
Compare("\u0131", "I", ignoreCase);
But we need to take a closer look at some specific functions. Looking at StringComparer in reflector, eventual it seems to go to:
case StringComparison.OrdinalIgnoreCase:
if (strA.IsAscii() && strB.IsAscii())
{
return nativeCompareOrdinal(strA, strB, true);
}
return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
And since we’re not talkin ASCII, TextInfo.CompareOrdinalIgnoreCase gets called:
internal static unsafe int CompareOrdinalIgnoreCase(string str1, string str2)
{
return nativeCompareOrdinalIgnoreCase(InvariantNativeTextInfo, str1, str2);
}
Which eventually interops with native libraries:
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe int nativeCompareOrdinalIgnoreCase(void* pNativeTextInfo, string str1, string str2);
It seems to be using the Win32 comparison functions for Unicode, presumably CompareString or CompareStringEx see http://msdn.microsoft.com/en-us/library/dd374047(VS.85).aspx#SC_comp_func.
If you can set a specific culture for, say, Turkey ‘tr-TR’ on the StringComparer, then both test cases return equal. I don’t get this because one of the tests would match if they were lowercased, while the other would match if uppercased, and I presumed there was only an uppercase comparison happening.
// Test StringComparer.Create with CreateSpecificCulture
if (sc.Compare(TestCases.Lowers, TestCases.ToLower) == 0)
{
Console.WriteLine("CreateSpecificCulture performs 'lowercase' comparisons: {0} and {1} are equal", TestCases.Lowers, TestCases.ToLower);
}
if (sc.Compare(TestCases.Uppers, TestCases.ToUpper) == 0)
{
Console.WriteLine("CreateSpecificCulture performs 'uppercase' comparisons: {0} and {1} are equal", TestCases.Uppers, TestCases.ToUpper);
}
The result of this is:
CreateSpecificCulture performs ‘lowercase’ comparisons: I and i are equal
CreateSpecificCulture performs ‘uppercase’ comparisons: i and I are equal
Tagged compare, string