System.AccessViolationException, сохраняющий переменную с reflectio.emit
В свободное время я создаю компилятор с mirror.emit, и у меня возникла проблема, которую я не понимаю.
Небольшой контекст, у меня есть среда выполнения с несколькими типами, и один из них - Float2, более простая векторная структура с двумя значениями с плавающей запятой (X и Y). Я сделал несколько свойств, которые позволяют мне менять значения (a la hlsl). Например, если у меня есть новый Float2(1.0f, 2.0f), если я сделаю что-то вроде (новый Float2(1.0f, 2.0f)).YX я собираюсь получить Float2(2.0f, 1.0f) I Я использую этот тип в моем языке и в настоящее время тестирую этот случай (незначительные детали языка опущены):
float2 a = float2(1.0, 2.0).yx;
return a;
Я преобразую float2(1.0, 2.0) в новый вызов и получаю доступ к свойству YX моего типа Float2 в.yx.
Проблема в том, что я получаю "System.AccessViolationException: попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена". Я не понимаю почему, потому что если я сделаю что-то вроде этого:
float2 a = float2(1.0, 2.0);
return a;
Все идет хорошо.
Код IL, который я генерирую, следующий (я думаю, что проблема возникает в "L_0014: stloc.0", хотя я не знаю, почему это происходит):
.method public virtual final instance valuetype
[Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 Main() cil managed
{
.maxstack 3
.locals init (
[0] valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 num)
L_0000: ldc.r4 1
L_0005: ldc.r4 2
L_000a: newobj instance void [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::.ctor(float32, float32)
L_000f: call instance valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::get_XY()
L_0014: stloc.0
L_0015: ldloc.0
L_0016: ret
}
Результат переверификации:
[IL]: Ошибка: [смещение 0x0000000F] [найденное значение 'Bifrost.Psl.Compiler.Runtime.Float2'][ожидаемый адрес значения 'Bifrost.Psl.Compiler.Runtime.Float2'] Неожиданный тип в стеке.
1 ответ
IL выглядит хорошо, хотя я не знаю, какова ваша Float2
похоже.
Я нашел лучший способ отладки: сохранить сборку на диск, а затем запустить peverify. Любой код, который генерирует AccessViolationException
вызовет ошибку в peverify.
Изменить: newobj
В документации по MSDN говорится о переносе ссылки на объект в стек, который я считал указателем на тип значения. Если вы получаете эту ошибку от peverify, то я думаю, что вам нужно
newobj
stloc
во временную переменнуюldloca
чтобы получить адрес типа значения, хранящегося во временной переменнойcall
Теперь, когда я думаю об этом, это то, что делает компилятор C#, если вы делаете прямой вызов для типа значения, такого как 4.ToString();
,