Может ли оператор C # генерировать несвязанный MSIL - PullRequest
7 голосов
/ 23 апреля 2019

Вопрос касается спецификации языка C # и спецификации языка CIL , а также поведения компилятора C # от Microsoft и Mono.

Я создаю несколько инструментов анализа кода (несмотря ни на что), которые работают на CIL.

Рассматривая несколько примеров кода, я заметил, что операторы кода (try / catch, ifelse, ifthen, loop, ...) генерируют связанные блоки MSIL.

Но я хотел бы быть уверен, что не могу написать конструкцию кода C #, которая выдает несвязанный MSIL.Более конкретно, могу ли я написать любое C # утверждение , которое переводится в (что-то похожее на):

IL_0000: 
IL_0001: 
IL_0002: 

// hole

IL_001a: 
IL_001b:

Я уже пробовал некоторые странные вещи, используя goto и вложенные циклы, но, возможно, яЯ не такой злой, как некоторые пользователи.

Ответы [ 2 ]

13 голосов
/ 23 апреля 2019

Конечно, это тривиально возможно.Что-то вроде:

static void M(bool x)
{
    if (x)
        return;
    else
        M(x);
    return;
}

Если вы скомпилируете это в режиме отладки, вы получите

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: stloc.0
    IL_0003: ldloc.0
    IL_0004: brfalse.s IL_0008
    IL_0006: br.s IL_0011
    IL_0008: ldarg.0
    IL_0009: call void A::M(bool)
    IL_000e: nop
    IL_000f: br.s IL_0011
    IL_0011: ret

Оператор if переходит с 0001 на 0009, и следствиеif - это переход к 0011;оба оператора return представляют собой один и тот же код, поэтому существует «дыра», содержащая nop и безусловная ветвь между основным телом if и последствием.

В более общем случае вам следуетникогда не предполагайте ничего о компоновке IL, созданной компилятором C #.Компилятор не дает никаких гарантий, кроме того, что созданный IL будет законным и, если это безопасно, проверяемым.


Вы говорите, что пишете некоторые инструменты анализа кода;как автор значительных частей анализатора C # и тот, кто работал над сторонними инструментами анализа в Coverity, совет: для большинства вопросов, на которые вы обычно хотите получить ответы о программах на C #, дерево разбора, созданное Roslyn, являетсясущность, которую вы хотите проанализировать, а не IL.Дерево разбора является конкретным синтаксическим деревом;это один-к-одному с каждым символом в исходном коде.Может быть очень сложно отобразить оптимизированный IL обратно в исходный исходный код, и может быть очень легко произвести ложные срабатывания в анализе IL.

Другими словами: источник-IL сохраняет семантику, но также теряет информацию;Обычно вы хотите проанализировать артефакт, в котором содержится наибольшее количество информации.

Если по какой-либо причине вам необходимо работать с анализатором на уровне IL, вашей первой задачей, вероятно, должно быть определение границ базового объекта.блоки, особенно если вы анализируете свойства достижимости.

«Базовый блок» - это непрерывный фрагмент IL, в котором конечная точка блока не «переходит» к следующей инструкции - потому что это, например, ветвление, возврат или выброс -и нет никаких ответвлений в блоке, кроме первой инструкции.

Затем вы можете сформировать график основных блоков для каждого метода, указав, какие из них могут передавать управление другим блокам.Это «поднимает уровень» вашего анализа;вместо того, чтобы анализировать эффекты последовательности инструкций IL, теперь вы анализируете эффекты графика базовых блоков.

Если вы скажете больше о том, какие виды анализа вы делаете, я могу посоветовать дальше.

1 голос
/ 23 апреля 2019

Теоретически да (это вытекает из моего опыта).Ваш инструмент анализа не работает непосредственно с c #, а работает только с IL-кодом.IL может быть создан любым, не только Visual Studio, но и другими языковыми компиляторами, такими как Visual Basic, Python.Нет ... и обфускаторы!Обфускаторы - настоящий виновник: в то время как другие компиляторы пытаются придерживаться спецификаций, обфускаторы делают все возможное, чтобы использовать спецификации и целевую среду выполнения.

Запутанный код может нарушать определенные шаблоны здравого смысла.Рассмотрим этот случай: некоторые умные обфускаторы создают недопустимый msil, но джиттер переваривает его, потому что случается так, что недействительные части в конце концов не выполняются.

При создании инструмента анализа вы не можете обрабатывать эти случаи, если толькоВаша цель - построить деобфускатор.

...