зеркало из https://github.com/mono/ikvm-fork.git
Bug fix. The local variable state at the end of an exception block (if the last instruction is a local variable store) needs to be merged into the exception handler state.
This commit is contained in:
Родитель
35d4dc950a
Коммит
a68002325d
|
@ -431,17 +431,7 @@ namespace IKVM.Internal
|
|||
{
|
||||
if (method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex)
|
||||
{
|
||||
// NOTE this used to be CopyLocalsAndSubroutines, but it doesn't (always) make
|
||||
// sense to copy the subroutine state
|
||||
// TODO figure out if there are circumstances under which it does make sense
|
||||
// to copy the active subroutine state
|
||||
// UPDATE subroutines must be copied as well, but I think I now have a better
|
||||
// understanding of subroutine merges, so the problems that triggered the previous
|
||||
// change here hopefully won't arise anymore
|
||||
InstructionState ex = state[i].CopyLocalsAndSubroutines();
|
||||
ex.PushObject();
|
||||
int idx = method.ExceptionTable[j].handlerIndex;
|
||||
state[idx] += ex;
|
||||
MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, state[i]);
|
||||
}
|
||||
}
|
||||
state[i].CopyTo(s);
|
||||
|
@ -1060,6 +1050,13 @@ namespace IKVM.Internal
|
|||
{
|
||||
throw new VerifyError("Stack size too large");
|
||||
}
|
||||
for (int j = 0; j < method.ExceptionTable.Length; j++)
|
||||
{
|
||||
if (method.ExceptionTable[j].endIndex == i + 1)
|
||||
{
|
||||
MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, s);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
// another big switch to handle the opcode targets
|
||||
|
@ -1278,6 +1275,20 @@ namespace IKVM.Internal
|
|||
}
|
||||
}
|
||||
|
||||
private void MergeExceptionHandler(int handlerIndex, InstructionState curr)
|
||||
{
|
||||
// NOTE this used to be CopyLocalsAndSubroutines, but it doesn't (always) make
|
||||
// sense to copy the subroutine state
|
||||
// TODO figure out if there are circumstances under which it does make sense
|
||||
// to copy the active subroutine state
|
||||
// UPDATE subroutines must be copied as well, but I think I now have a better
|
||||
// understanding of subroutine merges, so the problems that triggered the previous
|
||||
// change here hopefully won't arise anymore
|
||||
InstructionState ex = curr.CopyLocalsAndSubroutines();
|
||||
ex.PushObject();
|
||||
state[handlerIndex] += ex;
|
||||
}
|
||||
|
||||
private ClassFile.ConstantPoolItemMI GetMethodref(int index)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -421,6 +421,15 @@ struct LocalVarInfo
|
|||
&& (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0))))
|
||||
{
|
||||
curr.Store(i, instructions[i].NormalizedArg1);
|
||||
// if this is a store at the end of an exception block,
|
||||
// we need to propagate the new state to the exception handler
|
||||
for (int j = 0; j < exceptions.Length; j++)
|
||||
{
|
||||
if (exceptions[j].endIndex == i + 1)
|
||||
{
|
||||
state[exceptions[j].handlerIndex].Merge(curr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
|
||||
|
|
|
@ -1296,26 +1296,7 @@ sealed class MethodAnalyzer
|
|||
{
|
||||
if(method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex)
|
||||
{
|
||||
int idx = method.ExceptionTable[j].handlerIndex;
|
||||
InstructionState ex = state[i].CopyLocals();
|
||||
int catch_type = method.ExceptionTable[j].catch_type;
|
||||
if(catch_type == 0)
|
||||
{
|
||||
TypeWrapper tw;
|
||||
if (!faultTypes.TryGetValue(idx, out tw))
|
||||
{
|
||||
tw = VerifierTypeWrapper.MakeFaultBlockException(this, idx);
|
||||
faultTypes.Add(idx, tw);
|
||||
}
|
||||
ex.PushType(tw);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO if the exception type is unloadable we should consider pushing
|
||||
// Throwable as the type and recording a loader constraint
|
||||
ex.PushType(GetConstantPoolClassType(catch_type));
|
||||
}
|
||||
state[idx] += ex;
|
||||
MergeExceptionHandler(j, state[i]);
|
||||
}
|
||||
}
|
||||
state[i].CopyTo(s);
|
||||
|
@ -2275,6 +2256,13 @@ sealed class MethodAnalyzer
|
|||
{
|
||||
throw new VerifyError("Stack size too large");
|
||||
}
|
||||
for(int j = 0; j < method.ExceptionTable.Length; j++)
|
||||
{
|
||||
if(method.ExceptionTable[j].endIndex == i + 1)
|
||||
{
|
||||
MergeExceptionHandler(j, s);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
switch(ByteCodeMetaData.GetFlowControl(instr.NormalizedOpCode))
|
||||
|
@ -2327,6 +2315,30 @@ sealed class MethodAnalyzer
|
|||
}
|
||||
}
|
||||
|
||||
private void MergeExceptionHandler(int exceptionIndex, InstructionState curr)
|
||||
{
|
||||
int idx = method.ExceptionTable[exceptionIndex].handlerIndex;
|
||||
InstructionState ex = curr.CopyLocals();
|
||||
int catch_type = method.ExceptionTable[exceptionIndex].catch_type;
|
||||
if (catch_type == 0)
|
||||
{
|
||||
TypeWrapper tw;
|
||||
if (!faultTypes.TryGetValue(idx, out tw))
|
||||
{
|
||||
tw = VerifierTypeWrapper.MakeFaultBlockException(this, idx);
|
||||
faultTypes.Add(idx, tw);
|
||||
}
|
||||
ex.PushType(tw);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO if the exception type is unloadable we should consider pushing
|
||||
// Throwable as the type and recording a loader constraint
|
||||
ex.PushType(GetConstantPoolClassType(catch_type));
|
||||
}
|
||||
state[idx] += ex;
|
||||
}
|
||||
|
||||
// this verification pass must run on the unmodified bytecode stream
|
||||
private void VerifyPassTwo()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче