Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Wasm: change NRE handling from trap to exception (#8096)
Browse files Browse the repository at this point in the history
  • Loading branch information
yowl committed Apr 19, 2020
1 parent 4e02a11 commit 191a3c1
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 6 deletions.
22 changes: 16 additions & 6 deletions src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4210,20 +4210,30 @@ private void ThrowIfNull(LLVMValueRef entry)
var resultAddress = builder.BuildIntCast(builder.BuildAlloca(LLVMTypeRef.Int32, "resultAddress"), LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), "castResultAddress");
HandleDirectCall(helperMethod, helperMethod.Signature, arguments, null, default(LLVMValueRef), 0, NullRefFunction.GetParam(0), builder, true, resultAddress, helperMethod);

var exceptionEntry = new ExpressionEntry(GetStackValueKind(nullRefType), "RhNewObject_return", resultAddress, nullRefType);
var exceptionEntry = new LoadExpressionEntry(GetStackValueKind(nullRefType), "RhNewObject_return", resultAddress, nullRefType);

var ctorDef = nullRefType.GetDefaultConstructor();

var constructedExceptionObject = HandleDirectCall(ctorDef, ctorDef.Signature, new StackEntry[] { exceptionEntry }, null, default(LLVMValueRef), 0, NullRefFunction.GetParam(0), builder, false, default(LLVMValueRef), ctorDef);
HandleDirectCall(ctorDef, ctorDef.Signature, new StackEntry[] { exceptionEntry }, null, default(LLVMValueRef), 0, NullRefFunction.GetParam(0), builder, false, default(LLVMValueRef), ctorDef);

EmitTrapCall(builder);
EnsureRhpThrowEx();
LLVMValueRef[] args = new LLVMValueRef[] { exceptionEntry.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), builder) };
builder.BuildCall(RhpThrowEx, args, "");
builder.BuildUnreachable();
builder.PositionAtEnd(retBlock);
builder.BuildRetVoid();
}

LLVMValueRef shadowStack = _builder.BuildGEP(_currentFunclet.GetParam(0), new LLVMValueRef[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (uint)(GetTotalLocalOffset() + GetTotalParameterOffset()), false) }, String.Empty);
LLVMBasicBlockRef nextInstrBlock = default;
CallOrInvoke(false, _builder, GetCurrentTryRegion(), NullRefFunction, new List<LLVMValueRef> { GetShadowStack(), entry }, ref nextInstrBlock);
}

_builder.BuildCall(NullRefFunction, new LLVMValueRef[] { shadowStack, entry }, string.Empty);
void EnsureRhpThrowEx()
{
if (RhpThrowEx.Handle.Equals(IntPtr.Zero))
{
RhpThrowEx = Module.AddFunction("RhpThrowEx", LLVMTypeRef.CreateFunction(LLVMTypeRef.Void, new LLVMTypeRef[] { LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0) }, false));
}
}

private LLVMValueRef GetInstanceFieldAddress(StackEntry objectEntry, FieldDesc field)
Expand All @@ -4248,7 +4258,7 @@ private LLVMValueRef GetInstanceFieldAddress(StackEntry objectEntry, FieldDesc f
{
untypedObjectValue = objectEntry.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), _builder);
}

ThrowIfNull(untypedObjectValue);
if (field.Offset.AsInt == 0)
{
return untypedObjectValue;
Expand Down
43 changes: 43 additions & 0 deletions tests/src/Simple/HelloWasm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ private static unsafe int Main(string[] args)

TestInterlockedExchange();

TestThrowIfNull();

// This test should remain last to get other results before stopping the debugger
PrintLine("Debugger.Break() test: Ok if debugger is open and breaks.");
System.Diagnostics.Debugger.Break();
Expand Down Expand Up @@ -1633,6 +1635,42 @@ static void TestInterlockedExchange()
EndTest(exInt1 == 2 && exLong1 == 3);
}

static void TestThrowIfNull()
{
StartTest("TestThrowIfNull");
ClassForNre c = null;
var success = true;
try
{
var f = c.F; //field access
PrintLine("NRE Field access failed");
success = false;
}
catch(NullReferenceException)
{
}
catch(Exception)
{
success = false;
}

try
{
var f = c.ToString(); //method access
PrintLine("NRE method access failed");
success = false;
}
catch (NullReferenceException)
{
}
catch (Exception)
{
success = false;
}

EndTest(success);
}

static ushort ReadUInt16()
{
// something with MSB set
Expand All @@ -1649,6 +1687,11 @@ static ushort ReadUInt16()
private static unsafe extern int printf(byte* str, byte* unused);
}

public class ClassForNre
{
public int F;
}

public class ClassWithFloat
{
public static float F;
Expand Down

0 comments on commit 191a3c1

Please sign in to comment.