Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #204 — calling methods on null receiver does not crash #482

Merged
merged 1 commit into from
Jun 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/back/CodeGen/Expr.hs
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,12 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
in
do
typeArgs <- mapM getTypeVar typeParams
(nnew, ctorCall) <- namedTmpVar "new" ty callCtor
(nnew, constructorCall) <- namedTmpVar "new" ty callCtor
(initArgs, result) <-
methodCall nnew ty initName args ty
return (nnew,
Seq $
[ctorCall] ++
[constructorCall] ++
initArgs ++
[ Statement $ callTypeParamsInit $ (AsExpr nnew):typeArgs
, Statement result]
Expand Down Expand Up @@ -521,12 +521,13 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
(Call arraySize [ntarg])
return (Var tmp, Seq [ttarg, theSize])

translate call@(A.MethodCall { A.target, A.name, A.args})
translate call@(A.MethodCall { A.emeta, A.target, A.name, A.args})
| (Ty.isTraitType . A.getType) target = do
(ntarget, ttarget) <- translate target
(nCall, tCall) <- traitMethod ntarget (A.getType target) name args
(translate (A.getType call))
return (nCall, Seq $ ttarget : [tCall])
let recvNullCheck = targetNullCheck ntarget target name emeta "."
return (nCall, Seq $ ttarget : recvNullCheck : [tCall])
| syncAccess = delegateUse callTheMethodSync "sync_method_call"
| sharedAccess = delegateUse callTheMethodFuture "shared_method_call"
| isActive && isStream = delegateUse callTheMethodStream "stream"
Expand All @@ -543,6 +544,7 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
return (Var result,
Seq $
ttarget :
targetNullCheck ntarget target name emeta "." :
initArgs ++
[Assign (Decl (translate retTy, Var result)) resultExpr]
)
Expand All @@ -553,7 +555,7 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
isStream = Ty.isStreamType retTy
isFuture = Ty.isFutureType retTy

translate call@(A.MessageSend { A.target, A.name, A.args })
translate call@(A.MessageSend { A.emeta, A.target, A.name, A.args })
| (Ty.isActiveClassType . A.getType) target = messageSend
| sharedAccess = sharedObjectMethodOneWay call
| otherwise = error "Tried to send a message to something that was not an active reference"
Expand All @@ -563,7 +565,9 @@ instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where
messageSend =
do (ntarg, ttarg) <- translate target
theSend <- activeMessageSend ntarg (A.getType target) name args
return (unit, Seq (Comm "message send" : ttarg : [theSend]))
let recvNullCheck = targetNullCheck ntarg target name emeta
return (unit, Seq (Comm "message send" :
ttarg : recvNullCheck " ! " : [theSend]))

translate w@(A.While {A.cond, A.body}) =
do (ncond,tcond) <- translate cond
Expand Down Expand Up @@ -1273,3 +1277,12 @@ getTypeVar ty = do

msgSize :: CCode Ty -> CCode Expr
msgSize t = Call (Nam "POOL_INDEX") [Sizeof t]

targetNullCheck ntarget target name meta op =
Statement $
Call (Nam "check_reciever")
[AsExpr $ ntarget,
String op,
String (show (PP.ppExpr target)),
String (show name),
String (show (Meta.getPos meta))]
2 changes: 2 additions & 0 deletions src/runtime/encore/encore.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <pony.h>
#include <atomics.h>

#define check_reciever(this, op, recv, msg, file) if (!this) { fprintf(stderr, "Error: empty receiver in " recv op msg "(...) in " file "\n"); abort(); }

typedef struct context {
ucontext_t uctx;
struct context *next;
Expand Down
9 changes: 9 additions & 0 deletions src/tests/encore/basic/recvNullCall.enc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Main
def test() : void
print("If you can read this, then recvNullCall failed")
def main() : void
let
x = null:Main
in
x.test()

1 change: 1 addition & 0 deletions src/tests/encore/basic/recvNullCall.err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: empty receiver in x.test(...) in "recvNullCall.enc" (line 8, column 7)
9 changes: 9 additions & 0 deletions src/tests/encore/basic/recvNullSend.enc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Main
def test() : void
print("If you can read this, then recvNullSend failed")
def main() : void
let
x = null:Main
in
x ! test()

1 change: 1 addition & 0 deletions src/tests/encore/basic/recvNullSend.err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: empty receiver in x ! test(...) in "recvNullSend.enc" (line 8, column 9)