03 November, 2009

Ода гордости

Как это однако приятно увидеть, что результатом твоего труда пользуются в компании Microsoft. Смотреть тут! Для тех кто не в теме: стектрейсы сделаны моим детищем - JetBrains dotTrace 3.1.

23 October, 2009

Сюрприз

Ну вот, облизанный со всех сторон код рушится на моих глазах: RuntimeThreadSuspended и RuntimeThreadResumed оказывается могут вызываться из произвольного треда, а не только из того, что указан в аргументе. Получается, что повсеместно используемый TlsGetValue() именно в этих функциях со свистом пролетает мимо кассы. До сего момента я считал, что этим страдала только ThreadDestroyed, но там я выкрутился...

P.S. Иногда полезно быть параноиком и маниакально проверять в коде казалось бы очевидные вещи.

P.P.S. Если вы пользуетесь остановкой треда посредством DoStackSnapshot, то будьте готовы также получать и корректно обрабатывать RuntimeThreadSuspended и RuntimeThreadResumed.

21 October, 2009

Полезный тул

Каждый раз с завидным постоянством забываю название утилиты, которая показывает установленные .NET Compact Framework'и. Имя ей - cgacutil.exe. Надеюсь, что теперь не забуду.

23 September, 2009

Структура на стеке инструментируемой функции

Занимаясь инструментацией я пришел к выводу, что очень полезным является создание некой области на стеке функции для внутренних нужд профайлера. Для этого категорически необходимо создать структуру нужного размера. Увы, stackalloc не подходит так как требует довольно много накладных расходов и особенно под x64. Попытка использовать свой модуль с уже скомпилированными структурами во время работы профайлера приводит к зависанию во время загрузки оного. Поэтому пришлось в каждый модуль профилируемой программы эмитировать необходимую структуру.

Теперь о важном. Первое, что необходимо сделать - это найти mdAssemblyRef для mscorlob.dll и найти/создать mdTypeRef для System.ValueType - это необходимо, так как любая структура обязана иметь в качестве базового класса System.ValueType. Важно также чтобы наша структура имела атрибуты tdNotPublic, tdSequentialLayout, tdClass, tdSealed, tdBeforeFieldInit. И не забудьте установить необходимой вам class layout. Результатом всех этих действий будет mdTypeDef, который нужно засунуть в LocalVarSig.

Кстати в эту же структуру можно записывать (опять же с помощью той же инструментации) информацию о самой функции для профайлера - ну там statement count или еще что-нибудь нужное.

21 August, 2009

IL calling conversion

Единственная инструкция которая позволяет вызывать native код из IL есть calli. Возникает вопрос как нужно написать прототип функции на C++ для того чтобы передать аргументы из managed кода.

Для платформы x86 требуется чтобы функция была fastcall - первые два аргумента (те что передаются через регистры ECX и EDX) совпадают, а вот те аргументы которые лежат на стеке болжны быть описаны в обратном порядке (смотри MSDN x86 calling conversion а также Microsoft specific ECMA-335 Partition II 15.5.6.1). Привожу пример:

void fastcall MyOwnCallback(int arg0, int arg1, int arg4, int arg3, int arg2);

С платформой x64 еще проще используется стандартный calling conversion (смотри MSDN x64 calling conversion).

18 August, 2009

Очередной серьезный пробел в MSDN

Как жаль, что MSDN теперь пишут так халтурно, лучше бы сделали нормальную документацию, а не переводили это дерьмо на кучу языков отличных от английского. И вот я снова вляпался: есть такая функция SetILInstrumentedCodeMap() в качестве 4-ого аргумента у которой должен быть массив COR_IL_MAP. Нигде в MSDN не сказано, что этот самый массив обязательно нужно выделать с помощью CoTaskMemAlloc(). Уродство, так как это есть существенное поведение функции, увы, не отраженное в документации.

P.S. Мне помогло разобраться только капание в Shared CLI.

30 July, 2009

Пара слов про наследование handles

Все вы наверное не раз пользовались классом System.Diagnostics.Process для запуска процессов из под .NET приложения. Но не все знают что если ProcessStartInfo.UseShellExecute установлен в false, то все handle исходного процесса наследуются дочерним, если конечно иное не указано для конкретного handle. Все вышесказанное касается в одинаковой мере и .NET Framework, и .NET Compact Framework.

P.S. Кстати, всем C++ разработчикам известная, функция fopen по умолчанию не уcтанавливает флаг _O_NOINHERIT. Начиная с Visual Studio 2005 добавлен новый параметр N, который собственно и должен выставлять этот флаг в fopen. Увы в Windows CE нет такой возможности. Более того так как lpSecurityAttributes в функции CreateFile должен быть всегда NULL, то и установить переменную bInheritHandle в SECURITY_ATTRIBUTES тоже невозможно.

14 July, 2009

Найди отличия

Есть два по сути эквивалентных фрагмента кода на C#:
a(x => b().c(x));
и
a(b().c);
В какой момент произойдет NullReferenceException для каждого из вариантов, если b() всегда возвращает null?