Как компилятор Visual Studio компилирует атрибуты безопасности в CIL?

У меня есть следующий атрибут SecurityPermission(SecurityAction.Assert) в методе моего класса. Я компилирую его (отладочная сборка) и просматриваю вывод в ildasm.exe, просматривая необработанные кучи и просматривая кучу больших двоичных объектов, содержащую большой двоичный объект PermissionSet. Я ожидаю (согласно ECMA-335):

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  00 00

Но я увидел вот что:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  01 00

В частности, обратите внимание на 01 00 в конце, где я ожидал 00 00. В спецификации сказано, что после подсчитанной строки должно быть количество именованных аргументов. Поскольку я не передаю никаких именованных аргументов, я ожидал, что это число будет 16-битным 0.

Это скомпилировано против .NET 2.0 с использованием Visual Studio 2013.

Чтобы еще больше усложнить ситуацию, если я добавлю именованный аргумент, я получу следующее:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  12 01 54 02 0d 55 6e 6d >1934e089  T  Unm<
61 6e 61 67 65 64 43 6f  64 65 01                >anagedCode      <

Еще раз посмотрите на конец подсчитанной строки для атрибута, и вы увидите 12 01, за которым следует именованный список аргументов (список из одного элемента). Я ожидал, что это будет 01 00, 16-битный прямой порядок байтов 1 для количества именованных аргументов.

Исходя из этого, я предполагаю, что второй байт после подсчитанной строки является указанным количеством параметров, но я все еще не понимаю, что это за первый байт (0x01 в первом примере, 0x12 в следующем).

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

Я задаю этот вопрос, потому что пытаюсь вручную создать blob-объект PermissionSet (я пишу профилировщик CLR), и мне нужно знать, что вставить в этот байт.


person Micah Zoltu    schedule 24.12.2013    source источник
comment
Число похоже на количество байтов в подписи. В спецификации об этом не говорится и фактически говорится, что там должно быть 16-битное количество атрибутов, а не длина (возможно, сжатая), за которой следует 1-байтовый счетчик.   -  person Micah Zoltu    schedule 24.12.2013
comment
Обратитесь к главе II.23.3 и обратите внимание на значение Prolog. Это значение int16, равное 1, поэтому 0x01 0x00 в куче больших двоичных объектов. Избегайте самостоятельного анализа необработанных метаданных, у вас есть как управляемые, так и неуправляемые интерфейсы, которые могут сделать это за вас.   -  person Hans Passant    schedule 04.01.2014
comment
Я не смотрю на значение пролога, я смотрю на значение в позиции NumNamed, два байта после FixedArg на этой железнодорожной диаграмме. Кроме того, поскольку это атрибуты безопасности, а не пользовательские атрибуты, я не верю (и приведенный выше фрагмент байта соглашается), что в них есть пролог. См. ECMA 335 §II.22.11: Набор свойств, закодированных как именованные аргументы для настраиваемого атрибута, будет (как в §II.23.3, начиная с NumNamed).   -  person Micah Zoltu    schedule 04.01.2014
comment
Я внедряю метод с использованием неуправляемого API, и если я хочу прикрепить к нему атрибуты безопасности (или настраиваемые), мне нужно создать свои собственные подписи. Я следовал спецификации и столкнулся с проблемами, поэтому я разобрал метод с атрибутами безопасности, чтобы я мог видеть, что генерирует Visual Studio, и обнаружил это несоответствие между ним и спецификацией.   -  person Micah Zoltu    schedule 04.01.2014


Ответы (1)


Я думаю, что вы правы в своем смятении, я помню это из моего предыдущего опыта с именованными параметрами - NumNamed был реализован как сжатый int вместо int16, указанного в спецификации, и в отличие от примера, приведенного в §VI.B.3. Я не знаю, изменилось ли это в последующих реализациях .NET 3.0+.

Для PermissionSet, который вы ищете,

... * Набор свойств, закодированных как именованные аргументы настраиваемого атрибута, будет (как в §II.23.3, начиная с NumNamed).

... §II.23.3 ...

Далее следует описание необязательных «именованных» полей и свойств. Это начинается с NumNamed - беззнакового int16, указывающего количество «именованных» свойств или полей, которые следуют. ... В случае, когда NumNamed не равно нулю, за ним следуют повторения NumNamed для NamedArgs.

12 01 - это целое число с прямым порядком байтов, «задающее количество следующих свойств». Одно именованное свойство и общая длина 18 (в десятичной системе счисления включительно).

Эта общая длина является шаблоном, который вы искали, но будьте осторожны, поскольку я считаю, что эта длина необязательна, и иногда компилятору удается упаковать количество свойств в предыдущем int16, отбрасывая длину. Вам придется поэкспериментировать с другим количеством атрибутов, чтобы убедиться, что вы правильно разбираете все варианты.

NamesArgs:

... SerString - количество байтов PackedLen, за которым следуют символы UTF8

СВОЙСТВО - это однобайтный 0x54. FieldOrPropName - это имя поля или свойства, хранящееся как SerString (определено выше).

person mockinterface    schedule 04.01.2014
comment
Я пришел к такому же выводу, что это счетчик байтов, за которым следует один байт NumNamed. Это известная ошибка в компиляторе VS или что-то, что я должен сообщить им? - person Micah Zoltu; 04.01.2014
comment
Мне не известно об открытой ошибке, так что вы также можете зарегистрировать ее, но было бы лучше проверить, возникает ли эта проблема, если вы ориентируетесь на более свежие выпуски .NET. - person mockinterface; 05.01.2014
comment
Искал в Интернете сейчас, чтобы увидеть, есть ли открытая ошибка, и наткнулся на этот драгоценный камень в том, что кажется монореализацией, stuff.mit.edu/afs/athena/software/mono_v3.0/arch/ //. .. счетчик именованных аргументов представляет собой сжатое целое число (вместо UInt16 как NumNamed в настраиваемых атрибутах). Приносим извинения, если вам уже известен этот бит, HTH. - person mockinterface; 05.01.2014
comment
Хорошая находка на моно. Я буду работать над сообщением об ошибке (вероятно, в понедельник). - person Micah Zoltu; 05.01.2014
comment
Потрясающий. Как бы то ни было, я отчетливо помню, что это было не только сжатое целое число + длина, но иногда длина опускалась, если компилятору удавалось упаковать NumNamed в предыдущее целое число, принадлежащее общедоступному ключу, но я думаю, мы можем прояснить это если будет какой-то ответ от Microsoft. Ваше здоровье. - person mockinterface; 05.01.2014
comment
Сообщение об ошибке в Visual Studio: connect.microsoft.com/VisualStudio/feedback/details/840765/ - person Micah Zoltu; 26.03.2014
comment
Ошибка все еще существует в Roslyn. Я подал здесь исправление, но не ожидаю особого успеха: roslyn.codeplex.com/workitem / 75 - person Micah Zoltu; 12.04.2014