Commit c81a0ed3 authored by Russ Cox's avatar Russ Cox
Browse files

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 caug...
parent 52631983
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -33,18 +33,7 @@
// crosscall2(_cgo_allocate, &a, sizeof a);
// /* Here a.ret is a pointer to the allocated memory. */
static void
_cgo_allocate_internal(uintptr len, byte *ret)
{
CgoMal *c;
ret = runtime·mallocgc(len, nil, 0);
c = runtime·mallocgc(sizeof(*c), nil, 0);
c->next = g->m->cgomal;
c->alloc = ret;
g->m->cgomal = c;
FLUSH(&ret);
}
void runtime·_cgo_allocate_internal(void);
#pragma cgo_export_static _cgo_allocate
#pragma cgo_export_dynamic _cgo_allocate
......@@ -52,7 +41,7 @@ _cgo_allocate_internal(uintptr len, byte *ret)
void
_cgo_allocate(void *a, int32 n)
{
runtime·cgocallback((void(*)(void))_cgo_allocate_internal, a, n);
runtime·cgocallback((void(*)(void))runtime·_cgo_allocate_internal, a, n);
}
// Panic. The argument is converted into a Go string.
......@@ -63,18 +52,7 @@ _cgo_allocate(void *a, int32 n)
// crosscall2(_cgo_panic, &a, sizeof a);
// /* The function call will not return. */
extern void ·cgoStringToEface(String, Eface*);
static void
_cgo_panic_internal(byte *p)
{
String s;
Eface err;
s = runtime·gostring(p);
·cgoStringToEface(s, &err);
runtime·gopanic(err);
}
void runtime·_cgo_panic_internal(void);
#pragma cgo_export_static _cgo_panic
#pragma cgo_export_dynamic _cgo_panic
......@@ -82,7 +60,7 @@ _cgo_panic_internal(byte *p)
void
_cgo_panic(void *a, int32 n)
{
runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n);
runtime·cgocallback((void(*)(void))runtime·_cgo_panic_internal, a, n);
}
#pragma cgo_import_static x_cgo_init
......
......@@ -24,10 +24,3 @@ package cgo
*/
import "C"
// Supports _cgo_panic by converting a string constant to an empty
// interface.
func cgoStringToEface(s string, ret *interface{}) {
*ret = s
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import "unsafe"
// These functions are called from C code via cgo/callbacks.c.
// Allocate memory. This allocates the requested number of bytes in
// memory controlled by the Go runtime. The allocated memory will be
// zeroed. You are responsible for ensuring that the Go garbage
// collector can see a pointer to the allocated memory for as long as
// it is valid, e.g., by storing a pointer in a local variable in your
// C function, or in memory allocated by the Go runtime. If the only
// pointers are in a C global variable or in memory allocated via
// malloc, then the Go garbage collector may collect the memory.
//
// TODO(rsc,iant): This memory is untyped.
// Either we need to add types or we need to stop using it.
func _cgo_allocate_internal(len uintptr) unsafe.Pointer {
ret := gomallocgc(len, nil, 0)
c := new(cgomal)
c.alloc = ret
gp := getg()
c.next = gp.m.cgomal
gp.m.cgomal = c
return ret
}
// Panic.
func _cgo_panic_internal(p *byte) {
panic(gostringnocopy(p))
}
......@@ -711,7 +711,7 @@ dumpmemprof(void)
}
static void
mdump(G *gp)
mdump(void)
{
byte *hdr;
uintptr i;
......@@ -737,18 +737,32 @@ mdump(G *gp)
dumpmemprof();
dumpint(TagEOF);
flush();
gp->param = nil;
runtime·casgstatus(gp, Gwaiting, Grunning);
runtime·gogo(&gp->sched);
}
static void writeheapdump_m(void);
#pragma textflag NOSPLIT
void
runtimedebug·WriteHeapDump(uintptr fd)
{
void (*fn)(G*);
void (*fn)(void);
g->m->scalararg[0] = fd;
fn = writeheapdump_m;
runtime·onM(&fn);
}
static void
writeheapdump_m(void)
{
uintptr fd;
fd = g->m->scalararg[0];
g->m->scalararg[0] = 0;
// Stop the world.
runtime·casgstatus(g->m->curg, Grunning, Gwaiting);
g->waitreason = runtime·gostringnocopy((byte*)"dumping heap");
runtime·semacquire(&runtime·worldsema, false);
g->m->gcing = 1;
runtime·stoptheworld();
......@@ -761,11 +775,8 @@ runtime∕debug·WriteHeapDump(uintptr fd)
// Set dump file.
dumpfd = fd;
// Call dump routine on M stack.
runtime·casgstatus(g, Grunning, Gwaiting);
g->waitreason = runtime·gostringnocopy((byte*)"dumping heap");
fn = mdump;
runtime·mcall(&fn);
// Call dump routine.
mdump();
// Reset dump file.
dumpfd = 0;
......@@ -780,6 +791,7 @@ runtime∕debug·WriteHeapDump(uintptr fd)
g->m->locks++;
runtime·semrelease(&runtime·worldsema);
runtime·starttheworld();
runtime·casgstatus(g->m->curg, Gwaiting, Grunning);
g->m->locks--;
}
......
......@@ -124,9 +124,8 @@ static FinBlock *allfin; // list of all blocks
BitVector runtime·gcdatamask;
BitVector runtime·gcbssmask;
static Mutex gclock;
extern Mutex runtime·gclock;
static void bgsweep(void);
static Workbuf* getempty(Workbuf*);
static Workbuf* getfull(Workbuf*);
static void putempty(Workbuf*);
......@@ -137,7 +136,8 @@ static bool scanframe(Stkframe *frame, void *unused);
static void scanstack(G *gp);
static BitVector unrollglobgcprog(byte *prog, uintptr size);
static FuncVal bgsweepv = {bgsweep};
void runtime·bgsweep(void);
static FuncVal bgsweepv = {runtime·bgsweep};
static struct {
uint64 full; // lock-free list of full blocks
......@@ -1041,9 +1041,10 @@ runtime·MSpan_Sweep(MSpan *s, bool preserve)
return res;
}
// State of background sweep.
// Pretected by gclock.
static struct
// State of background runtime·sweep.
// Pretected by runtime·gclock.
// Must match mgc0.go.
struct
{
G* g;
bool parked;
......@@ -1052,29 +1053,7 @@ static struct
uint32 nbgsweep;
uint32 npausesweep;
} sweep;
// background sweeping goroutine
static void
bgsweep(void)
{
g->issystem = true;
for(;;) {
while(runtime·sweepone() != -1) {
sweep.nbgsweep++;
runtime·gosched();
}
runtime·lock(&gclock);
if(!runtime·mheap.sweepdone) {
// It's possible if GC has happened between sweepone has
// returned -1 and gclock lock.
runtime·unlock(&gclock);
continue;
}
sweep.parked = true;
runtime·parkunlock(&gclock, runtime·gostringnocopy((byte*)"GC sweep wait"));
}
}
} runtime·sweep;
// sweeps one span
// returns number of pages returned to heap, or -1 if there is nothing to sweep
......@@ -1090,7 +1069,7 @@ runtime·sweepone(void)
g->m->locks++;
sg = runtime·mheap.sweepgen;
for(;;) {
idx = runtime·xadd(&sweep.spanidx, 1) - 1;
idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1;
if(idx >= work.nspan) {
runtime·mheap.sweepdone = true;
g->m->locks--;
......@@ -1111,6 +1090,30 @@ runtime·sweepone(void)
}
}
static void
sweepone_m(void)
{
g->m->scalararg[0] = runtime·sweepone();
}
#pragma textflag NOSPLIT
uintptr
runtime·gosweepone(void)
{
void (*fn)(void);
fn = sweepone_m;
runtime·onM(&fn);
return g->m->scalararg[0];
}
#pragma textflag NOSPLIT
bool
runtime·gosweepdone(void)
{
return runtime·mheap.sweepdone;
}
void
runtime·gchelper(void)
{
......@@ -1328,7 +1331,7 @@ gc(struct gc_args *args)
// Sweep what is not sweeped by bgsweep.
while(runtime·sweepone() != -1)
sweep.npausesweep++;
runtime·sweep.npausesweep++;
// Cache runtime.mheap.allspans in work.spans to avoid conflicts with
// resizing/freeing allspans.
......@@ -1407,11 +1410,11 @@ gc(struct gc_args *args)
mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
heap0>>20, heap1>>20, obj,
mstats.nmalloc, mstats.nfree,
work.nspan, sweep.nbgsweep, sweep.npausesweep,
work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep,
stats.nhandoff, stats.nhandoffcnt,
work.markfor->nsteal, work.markfor->nstealcnt,
stats.nprocyield, stats.nosyield, stats.nsleep);
sweep.nbgsweep = sweep.npausesweep = 0;
runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0;
}
// See the comment in the beginning of this function as to why we need the following.
......@@ -1426,23 +1429,23 @@ gc(struct gc_args *args)
runtime·mheap.sweepdone = false;
work.spans = runtime·mheap.allspans;
work.nspan = runtime·mheap.nspan;
sweep.spanidx = 0;
runtime·sweep.spanidx = 0;
runtime·unlock(&runtime·mheap.lock);
// Temporary disable concurrent sweep, because we see failures on builders.
if(ConcurrentSweep && !args->eagersweep) {
runtime·lock(&gclock);
if(sweep.g == nil)
sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc);
else if(sweep.parked) {
sweep.parked = false;
runtime·ready(sweep.g);
runtime·lock(&runtime·gclock);
if(runtime·sweep.g == nil)
runtime·sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc);
else if(runtime·sweep.parked) {
runtime·sweep.parked = false;
runtime·ready(runtime·sweep.g);
}
runtime·unlock(&gclock);
runtime·unlock(&runtime·gclock);
} else {
// Sweep all spans eagerly.
while(runtime·sweepone() != -1)
sweep.npausesweep++;
runtime·sweep.npausesweep++;
}
runtime·mProf_GC();
......@@ -1451,9 +1454,27 @@ gc(struct gc_args *args)
extern uintptr runtime·sizeof_C_MStats;
static void readmemstats_m(void);
#pragma textflag NOSPLIT
void
runtime·ReadMemStats(MStats *stats)
{
void (*fn)(void);
g->m->ptrarg[0] = stats;
fn = readmemstats_m;
runtime·onM(&fn);
}
static void
readmemstats_m(void)
{
MStats *stats;
stats = g->m->ptrarg[0];
g->m->ptrarg[0] = nil;
// Have to acquire worldsema to stop the world,
// because stoptheworld can only be used by
// one goroutine at a time, and there might be
......@@ -1478,11 +1499,28 @@ runtime·ReadMemStats(MStats *stats)
g->m->locks--;
}
static void readgcstats_m(void);
#pragma textflag NOSPLIT
void
runtimedebug·readGCStats(Slice *pauses)
{
void (*fn)(void);
g->m->ptrarg[0] = pauses;
fn = readgcstats_m;
runtime·onM(&fn);
}
static void
readgcstats_m(void)
{
Slice *pauses;
uint64 *p;
uint32 i, n;
pauses = g->m->ptrarg[0];
g->m->ptrarg[0] = nil;
// Calling code in runtime/debug should make the slice large enough.
if(pauses->cap < nelem(mstats.pause_ns)+3)
......@@ -1510,7 +1548,8 @@ runtime∕debug·readGCStats(Slice *pauses)
}
void
runtime·setgcpercent_m(void) {
runtime·setgcpercent_m(void)
{
int32 in;
int32 out;
......@@ -1901,7 +1940,8 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
void runtime·gc_unixnanotime(int64 *now);
int64 runtime·unixnanotime(void)
int64
runtime·unixnanotime(void)
{
int64 now;
......
......@@ -68,3 +68,38 @@ func clearpools() {
}
}
}
// State of background sweep.
// Protected by gclock.
// Must match mgc0.c.
var sweep struct {
g *g
parked bool
spanidx uint32 // background sweeper position
nbgsweep uint32
npausesweep uint32
}
var gclock mutex // also in mgc0.c
func gosweepone() uintptr
func gosweepdone() bool
func bgsweep() {
getg().issystem = true
for {
for gosweepone() != ^uintptr(0) {
sweep.nbgsweep++
gosched()
}
lock(&gclock)
if !gosweepdone() {
// This can happen if a GC runs between
// gosweepone returning ^0 above
// and the lock being acquired.
unlock(&gclock)
continue
}
sweep.parked = true
goparkunlock(&gclock, "GC sweep wait")
}
}
......@@ -498,41 +498,6 @@ runtime·mach_semrelease(uint32 sem)
}
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
#pragma textflag NOSPLIT
void
runtime·osyield(void)
......@@ -593,3 +558,10 @@ runtime·unblocksignals(void)
{
runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -215,41 +215,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -338,3 +303,10 @@ runtime·unblocksignals(void)
{
runtime·sigprocmask(&sigset_none, nil);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -223,41 +223,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -346,3 +311,10 @@ runtime·unblocksignals(void)
{
runtime·sigprocmask(&sigset_none, nil);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -237,41 +237,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -368,3 +333,10 @@ runtime·unblocksignals(void)
{
runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -291,19 +291,6 @@ runtime·closeonexec(int32)
{
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
// Native Client only invokes the exception handler for memory faults.
g->sig = SIGSEGV;
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
uint32 runtime·writelock; // test-and-set spin lock for runtime.write
/*
......
......@@ -28,3 +28,14 @@ const stackSystem = 0
func os_sigpipe() {
gothrow("too many writes on closed pipe")
}
func sigpanic() {
g := getg()
if !canpanic(g) {
gothrow("unexpected signal during runtime execution")
}
// Native Client only invokes the exception handler for memory faults.
g.sig = _SIGSEGV
panicmem()
}
......@@ -293,41 +293,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -394,3 +359,10 @@ runtime·unblocksignals(void)
{
runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -248,41 +248,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -346,3 +311,10 @@ runtime·unblocksignals(void)
{
runtime·sigprocmask(SIG_SETMASK, sigset_none);
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
......@@ -326,84 +326,6 @@ runtime·semawakeup(M *mp)
runtime·plan9_semrelease(&mp->waitsemacount, 1);
}
static int64
atolwhex(byte *p)
{
int64 n;
int32 f;
n = 0;
f = 0;
while(*p == ' ' || *p == '\t')
p++;
if(*p == '-' || *p == '+') {
if(*p++ == '-')
f = 1;
while(*p == ' ' || *p == '\t')
p++;
}
if(p[0] == '0' && p[1]) {
if(p[1] == 'x' || p[1] == 'X') {
p += 2;
for(;;) {
if('0' <= *p && *p <= '9')
n = n*16 + *p++ - '0';
else if('a' <= *p && *p <= 'f')
n = n*16 + *p++ - 'a' + 10;
else if('A' <= *p && *p <= 'F')
n = n*16 + *p++ - 'A' + 10;
else
break;
}
} else
while('0' <= *p && *p <= '7')
n = n*8 + *p++ - '0';
} else
while('0' <= *p && *p <= '9')
n = n*10 + *p++ - '0';
if(f)
n = -n;
return n;
}
void
runtime·sigpanic(void)
{
byte *p;
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGRFAULT:
case SIGWFAULT:
p = runtime·strstr((byte*)g->m->notesig, (byte*)"addr=")+5;
g->sigcode1 = atolwhex(p);
if(g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
break;
case SIGTRAP:
if(g->paniconfault)
runtime·panicstring("invalid memory address or nil pointer dereference");
runtime·throw(g->m->notesig);
break;
case SIGINTDIV:
runtime·panicstring("integer divide by zero");
break;
case SIGFLOAT:
runtime·panicstring("floating point error");
break;
default:
runtime·panicstring(g->m->notesig);
break;
}
}
#pragma textflag NOSPLIT
int32
runtime·read(int32 fd, void *buf, int32 nbytes)
......
......@@ -32,3 +32,75 @@ type _Plink uintptr
func os_sigpipe() {
gothrow("too many writes on closed pipe")
}
func sigpanic() {
g := getg()
if !canpanic(g) {
gothrow("unexpected signal during runtime execution")
}
note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
switch g.sig {
case _SIGRFAULT, _SIGWFAULT:
addr := note[index(note, "addr=")+5:]
g.sigcode1 = uintptr(atolwhex(addr))
if g.sigcode1 < 0x1000 || g.paniconfault {
panicmem()
}
print("unexpected fault address ", hex(g.sigcode1), "\n")
gothrow("fault")
case _SIGTRAP:
if g.paniconfault {
panicmem()
}
gothrow(note)
case _SIGINTDIV:
panicdivide()
case _SIGFLOAT:
panicfloat()
default:
panic(errorString(note))
}
}
func atolwhex(p string) int64 {
for hasprefix(p, " ") || hasprefix(p, "\t") {
p = p[1:]
}
neg := false
if hasprefix(p, "-") || hasprefix(p, "+") {
neg = p[0] == '-'
p = p[1:]
for hasprefix(p, " ") || hasprefix(p, "\t") {
p = p[1:]
}
}
var n int64
switch {
case hasprefix(p, "0x"), hasprefix(p, "0X"):
p = p[2:]
for ; len(p) > 0; p = p[1:] {
if '0' <= p[0] && p[0] <= '9' {
n = n*16 + int64(p[0]-'0')
} else if 'a' <= p[0] && p[0] <= 'f' {
n = n*16 + int64(p[0]-'a'+10)
} else if 'A' <= p[0] && p[0] <= 'F' {
n = n*16 + int64(p[0]-'A'+10)
} else {
break
}
}
case hasprefix(p, "0"):
for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] {
n = n*8 + int64(p[0]-'0')
}
default:
for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] {
n = n*10 + int64(p[0]-'0')
}
}
if neg {
n = -n
}
return n
}
......@@ -194,41 +194,6 @@ runtime·unminit(void)
runtime·signalstack(nil, 0);
}
void
runtime·sigpanic(void)
{
if(!runtime·canpanic(g))
runtime·throw("unexpected signal during runtime execution");
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
}
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
runtime·panicstring("integer overflow");
}
runtime·panicstring("floating point error");
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
uintptr
runtime·memlimit(void)
{
......@@ -580,3 +545,10 @@ runtime·osyield(void)
}
runtime·osyield1();
}
#pragma textflag NOSPLIT
int8*
runtime·signame(int32 sig)
{
return runtime·sigtab[sig].name;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment