Отладка строкового значения .Net в windbg - PullRequest
8 голосов
/ 07 июня 2011

У меня есть дамп приложения .Net, который захватил исключение, я анализирую с помощью windbg и заинтересован в значении параметра String в одном из методов. Я изолировал объект String. Моя работа с Windbg:

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 <<

Переменная-член m_stringLength указывает, что длина строки составляет 179 символов, однако при проверке строки она кажется длиной всего 32 символа. Глядя на память для этой строки, похоже, завершается NULL. После завершающего символа NULL больше символов. Это может быть повторное использование памяти или повреждение строки, однако путь выглядит правильно, как показано Исключением является «Недопустимые символы в пути», но в этом пути нет недопустимых символов. Таким образом, стек вызовов для этого исключения:

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)

Обрабатывает ли метод System.IO.Path.CheckInvalidPathChars строку, используя длину, указанную в m_stringLength, или учитывает завершение NULL в самой строке? Я также открыт к тому факту, что есть что-то еще не так, если вы можете обнаружить то, чего у меня нет.

Ответы [ 2 ]

5 голосов
/ 07 июня 2011

Я бы выгружал фактическую строку из памяти в файл, чтобы проверить содержимое, а не просто просматривал вывод в windbg.

Вот сценарий Windbg, который я написал некоторое время назад, чтобы сбросить строки вфайл.

$$ 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
}

Вся идея состоит в том, чтобы использовать команду .writemem для выгрузки содержимого в файл.

Выведенное содержимое будет в формате Unicode и для просмотра его содержимогоиспользуйте что-то вроде этого

Console.WriteLine(ASCIIEncoding.Unicode.GetString(File.ReadAllBytes(@"c:\temp\stringtest03575270.txt")));

HTH

1 голос
/ 07 июня 2011

Вот что делает System.IO.Path.CheckInvalidPathChars (по крайней мере, в .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"));
    }
}

Обратите внимание, что интересная часть string.Length, то есть то, как строка на самом деле представляет еесвойство length отсутствует:

public int Length { [MethodImpl(MethodImplOptions.InternalCall)] get; }

Я бы попытался смоделировать проблему, если это возможно, путем получения точной строки (вплоть до длины, хранящейся в m_stringLength) и попытки воспроизвести проблему.

...