Поведение делегата CIL с конфликтующей «статичностью» целевого метода

Этот вопрос потребует небольшого введения.

Я работаю над проект безопасности, который будет анализировать сборки CIL и отклонять те, которые делают определенные «плохие» вещи, а также позволяет хост-приложению предоставлять «ворота» для некоторых методов, чтобы разрешить фильтрацию некоторых вызовов. (Это небольшая часть функциональности проекта, но это та часть, о которой я буду спрашивать здесь.)

Проект сканирует все инструкции в каждом методе сборки и ищет вызов callvirt , ldftn, ldvirtftn и newobj коды операций, так как это единственные коды операций, которые в конечном итоге могут привести к вызову метода. Коды операций ldftn используются при создании делегатов, например:

ldarg.1
ldftn instance bool string::EndsWith(string)
newobj instance void class [System.Core]System.Func`2<string, bool>::'.ctor'(object, native int)

В конце этой последовательности Func находится наверху стека.

Допустим, я хотите перехватить все вызовы String.EndsWith (String) . Для call и callvirt я могу просто заменить вызов экземпляра статическим вызовом сигнатуры Boolean (String, String) - первым аргументом будет экземпляр строки, для которого метод был первоначально вызван. На уровне CIL поведение будет однозначным и четко определенным, поскольку именно так вызываются статические методы.

Но для ldftn? Я попытался просто заменить операнд инструкции ldftn тем же статическим методом, который использовался для замены операнда call / callvirt:

ldarg.1
ldftn bool class Prototype.Program::EndsWithGate(string, string)
newobj instance void class [System.Core]System.Func`2<string, bool>::'.ctor'(object, native int)

Я полностью ожидал, что это не удастся, так как делегату предоставляется целевой объект (не null) при передаче статического указатель метода. К моему удивлению, это действительно работает как в среде выполнения Microsoft .NET, так и в Mono. Я понимаю, что параметр target / this - всего лишь первый параметр метода и скрыт, например, для методов. (Проект основан на этом знании.) Но тот факт, что делегаты действительно работают в этих обстоятельствах, немного озадачивает меня.

Итак, мой вопрос: это определенное и задокументированное поведение? Будет ли делегат при вызове, всегда помещать свою цель в стек, если она не равна нулю? Было бы лучше создать закрывающий класс, который будет захватывать цель и «должным образом» вызывать статический метод, даже если это будет намного сложнее и раздражает?

5
задан cdhowie 12 December 2010 в 22:17
поделиться