I have a .Net application dump which captured an exception, I'm analysing using windbg and interested in the value of a String parameter on one of the methods. I've isolated the String object. My windbg working is:
0:000> .loadby sos mscorwks
0:000> !dso
OS Thread Id: 0x16f0 (0)
RSP/REG Object Name
00000000001fe908 000000000f011440 System.AppDomainSetup
00000000001fe918 000000000f0335f8 System.ArgumentException
00000000001fe920 000000000f011b60 System.String
0:000> !do 000000000f011b60
Name: System.String
MethodTable: 000007feef477a80
EEClass: 000007feef07e530
Size: 538(0x21a) bytes
(C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: C:\Windows\Installer\MSI2D87.tmp
Fields:
MT Field Offset Type VT Attr Value Name
000007feef47ecf0 4000096 8 System.Int32 1 instance 257 m_arrayLength
000007feef47ecf0 4000097 c System.Int32 1 instance 179 m_stringLength
000007feef4794c8 4000098 10 System.Char 1 instance 43 m_firstChar
000007feef477a80 4000099 20 System.String 0 shared static Empty
>> Domain:Value 00000000029d02d0:000000000f011308 <<
000007feef479378 400009a 28 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 00000000029d02d0:000000000f0121f8 <<
The m_stringLength member variable indicates that the string is 179 characters long, however inspecting the string it seems to be only 32 characters long. Looking at the memory for this string is appears to be NULL terminated. There are more characters after the NULL terminating character. This may be reused memory or a string corruption however the path looks correct as displayed. The exception being thrown is 'Illegal characters in path' but there are no illegal characters in this path. So the call stack for this exception is:
0:000> !CLRStack
OS Thread Id: 0xbac (0)
Child-SP RetAddr Call Site
000000000021e9a0 000007feeea64dec System.IO.Path.CheckInvalidPathChars(System.String)
000000000021e9e0 000007feee9c0e66 System.IO.Path.NormalizePathFast(System.String, Boolean)
000000000021eaa0 000007feee9badf8 System.AppDomainSetup.NormalizePath(System.String, Boolean)
000000000021eb10 000007feeea630ad System.AppDomainSetup.SetupDefaultApplicationBase(System.String)
000000000021eb70 000007feee9bb27b System.AppDomain.SetupFusionStore(System.AppDomainSetup)
000000000021ebc0 000007feef87d4a2 System.AppDomain.SetupDomain(Boolean, System.String, System.String)
Does the System.IO.Path.CheckInvalidPathChars method process the string using the length found in m_stringLength, or does it take into account the NULL termination in the string itself? I'm also open to the fact that there is something else wrong if you can spot something I haven't.
I would dump the actual string from the memory in to file to check the contents instead of just looking at the output within windbg.
Here is a Windbg script I wrote a while back to dump the strings to a file.
$$ Dumps the managed strings to a file
$$ Platform x86
$$ Usage $$>a<"c:\temp\dumpstringtofolder.txt" 6544f9ac 5000 c:\temp\stringtest
$$ First argument is the string method table pointer
$$ Second argument is the Min size of the string that needs to be used filter the strings
$$ Third is the path of the file
.foreach ($string {!dumpheap -short -mt ${$arg1} -min ${$arg2}})
{
$$ MT Field Offset Type VT Attr Value Name
$$ 65452978 40000ed 4 System.Int32 1 instance 71117 m_stringLength
$$ 65451dc8 40000ee 8 System.Char 1 instance 3c m_firstChar
$$ 6544f9ac 40000ef 8 System.String 0 shared static Empty
$$ start of string is stored in the 8th offset, which can be inferred from above
$$ Size of the string which is stored in the 4th offset
r@$t0= poi(${$string}+4)*2
.writemem ${$arg3}${$string}.txt ${$string}+8 ${$string}+8+@$t0
}
The whole idea is to use the .writemem
command to dump the contents to a file.
The dumped contents would be in Unicode format and to view its contents use something like this
Console.WriteLine(ASCIIEncoding.Unicode.GetString(File.ReadAllBytes(@"c:\temp\stringtest03575270.txt")));
HTH
Here's what System.IO.Path.CheckInvalidPathChars is doing (at least in .NET 2.0):
for (int i = 0; i < path.Length; i++)
{
int num2 = path[i];
if (((num2 == 0x22) || (num2 == 60)) || (((num2 == 0x3e) || (num2 == 0x7c)) || (num2 < 0x20)))
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
}
}
Note that the interesting part of string.Length, that is, how string actually exposes its length property, is missing:
public int Length { [MethodImpl(MethodImplOptions.InternalCall)] get; }
I would try to simulate the issue if possible, by retrieving the exact string (up to to length stored in m_stringLength) and trying to reproduce the issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With