diff options
author | Russ Cox <rsc@golang.org> | 2014-09-08 14:05:23 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-09-08 14:05:23 -0400 |
commit | 9ad3fba8367769ee742f07e83aa714c9ae6b8d8a (patch) | |
tree | 927a0d6982e643c90edd5ddefaf706b4d20bd984 /src/liblink | |
parent | 87cb94fa270003e8d950d001e1c85e34a5457a8a (diff) | |
download | go-9ad3fba8367769ee742f07e83aa714c9ae6b8d8a.tar.gz |
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes issue 8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://codereview.appspot.com/133700043
Diffstat (limited to 'src/liblink')
-rw-r--r-- | src/liblink/obj5.c | 7 | ||||
-rw-r--r-- | src/liblink/obj6.c | 11 | ||||
-rw-r--r-- | src/liblink/obj8.c | 11 |
3 files changed, 27 insertions, 2 deletions
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c index 6630a5923..d9f980aca 100644 --- a/src/liblink/obj5.c +++ b/src/liblink/obj5.c @@ -769,6 +769,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) p->as = AMOVW; p->from.type = D_OREG; p->from.reg = REGG; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_REG; p->to.reg = 1; @@ -884,7 +886,10 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) p->as = ABL; p->scond = C_SCOND_LS; p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[noctxt]; + if(ctxt->cursym->cfunc) + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + else + p->to.sym = ctxt->symmorestack[noctxt]; // BLS start p = appendp(ctxt, p); diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c index 6a7ff48b0..572219b5b 100644 --- a/src/liblink/obj6.c +++ b/src/liblink/obj6.c @@ -783,6 +783,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_SP; indir_cx(ctxt, &p->to); + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAQ -xxx(SP), AX @@ -797,6 +799,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_AX; indir_cx(ctxt, &p->to); + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else { // Such a large stack we need to protect against wraparound. // If SP is close to zero: @@ -817,6 +821,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = mov; indir_cx(ctxt, &p->from); p->from.offset = 0; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_SI; p = appendp(ctxt, p); @@ -873,6 +879,11 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(ctxt, p); + if(ctxt->cursym->cfunc) { + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + } else if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c index 03f12462e..d8a93fb57 100644 --- a/src/liblink/obj8.c +++ b/src/liblink/obj8.c @@ -539,6 +539,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAL -(framesize-StackSmall)(SP), AX @@ -553,6 +555,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else { // Such a large stack we need to protect against wraparound // if SP is close to zero. @@ -572,6 +576,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = AMOVL; p->from.type = D_INDIR+D_CX; p->from.offset = 0; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_SI; p = appendp(ctxt, p); @@ -641,7 +647,10 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p = appendp(ctxt, p); p->as = ACALL; p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[noctxt]; + if(ctxt->cursym->cfunc) + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + else + p->to.sym = ctxt->symmorestack[noctxt]; p = appendp(ctxt, p); p->as = AJMP; |