reflect, runtime: Let reflect.MakeFunc functions call recover.

From-SVN: r205908
This commit is contained in:
Ian Lance Taylor 2013-12-11 23:43:16 +00:00
parent de04d95e64
commit b1d137cf58
6 changed files with 109 additions and 2 deletions

View File

@ -48,6 +48,15 @@ reflect.makeFuncStub:
leal 8(%ebp), %eax /* Set esp field in struct. */ leal 8(%ebp), %eax /* Set esp field in struct. */
movl %eax, -24(%ebp) movl %eax, -24(%ebp)
/* For MakeFunc functions that call recover. */
movl 4(%ebp), %eax
movl %eax, (%esp)
#ifdef __PIC__
call __go_makefunc_can_recover@PLT
#else
call __go_makefunc_can_recover
#endif
#ifdef __PIC__ #ifdef __PIC__
call __go_get_closure@PLT call __go_get_closure@PLT
#else #else
@ -65,6 +74,13 @@ reflect.makeFuncStub:
call reflect.MakeFuncStubGo call reflect.MakeFuncStubGo
#endif #endif
/* MakeFunc functions can no longer call recover. */
#ifdef __PIC__
call __go_makefunc_returning@PLT
#else
call __go_makefunc_returning
#endif
/* Set return registers. */ /* Set return registers. */
movl -20(%ebp), %eax movl -20(%ebp), %eax

View File

@ -61,6 +61,14 @@ reflect.makeFuncStub:
movdqa %xmm6, 0xa0(%rsp) movdqa %xmm6, 0xa0(%rsp)
movdqa %xmm7, 0xb0(%rsp) movdqa %xmm7, 0xb0(%rsp)
/* For MakeFunc functions that call recover. */
movq 8(%rbp), %rdi
#ifdef __PIC__
call __go_makefunc_can_recover@PLT
#else
call __go_makefunc_can_recover
#endif
# Get function type. # Get function type.
#ifdef __PIC__ #ifdef __PIC__
call __go_get_closure@PLT call __go_get_closure@PLT
@ -77,6 +85,13 @@ reflect.makeFuncStub:
call reflect.MakeFuncStubGo call reflect.MakeFuncStubGo
#endif #endif
/* MakeFunc functions can no longer call recover. */
#ifdef __PIC__
call __go_makefunc_returning@PLT
#else
call __go_makefunc_returning
#endif
# The structure will be updated with any return values. Load # The structure will be updated with any return values. Load
# all possible return registers before returning to the caller. # all possible return registers before returning to the caller.

View File

@ -27,6 +27,7 @@ __go_defer (_Bool *frame, void (*pfn) (void *), void *arg)
n->__pfn = pfn; n->__pfn = pfn;
n->__arg = arg; n->__arg = arg;
n->__retaddr = NULL; n->__retaddr = NULL;
n->__makefunc_can_recover = 0;
g->defer = n; g->defer = n;
} }

View File

@ -34,4 +34,10 @@ struct __go_defer_stack
set by __go_set_defer_retaddr which is called by the thunks set by __go_set_defer_retaddr which is called by the thunks
created by defer statements. */ created by defer statements. */
const void *__retaddr; const void *__retaddr;
/* Set to true if a function created by reflect.MakeFunc is
permitted to recover. The return address of such a function
function will be somewhere in libffi, so __retaddr is not
useful. */
_Bool __makefunc_can_recover;
}; };

View File

@ -16,12 +16,14 @@
__go_can_recover--this is, the thunk. */ __go_can_recover--this is, the thunk. */
_Bool _Bool
__go_can_recover (const void* retaddr) __go_can_recover (const void *retaddr)
{ {
G *g; G *g;
struct __go_defer_stack *d; struct __go_defer_stack *d;
const char* ret; const char* ret;
const char* dret; const char* dret;
Location loc;
const byte *name;
g = runtime_g (); g = runtime_g ();
@ -52,7 +54,73 @@ __go_can_recover (const void* retaddr)
#endif #endif
dret = (const char *) d->__retaddr; dret = (const char *) d->__retaddr;
return ret <= dret && ret + 16 >= dret; if (ret <= dret && ret + 16 >= dret)
return 1;
/* If the function calling recover was created by reflect.MakeFunc,
then RETADDR will be somewhere in libffi. Our caller is
permitted to recover if it was called from libffi. */
if (!d->__makefunc_can_recover)
return 0;
if (runtime_callers (2, &loc, 1) < 1)
return 0;
/* If we have no function name, then we weren't called by Go code.
Guess that we were called by libffi. */
if (loc.function.len == 0)
return 1;
if (loc.function.len < 4)
return 0;
name = loc.function.str;
if (*name == '_')
{
if (loc.function.len < 5)
return 0;
++name;
}
if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
return 1;
return 0;
}
/* This function is called when code is about to enter a function
created by reflect.MakeFunc. It is called by the function stub
used by MakeFunc. If the stub is permitted to call recover, then a
real MakeFunc function is permitted to call recover. */
void
__go_makefunc_can_recover (const void *retaddr)
{
struct __go_defer_stack *d;
d = runtime_g ()->defer;
if (d != NULL
&& !d->__makefunc_can_recover
&& __go_can_recover (retaddr))
d->__makefunc_can_recover = 1;
}
/* This function is called when code is about to exit a function
created by reflect.MakeFunc. It is called by the function stub
used by MakeFunc. It clears the __makefunc_can_recover field.
It's OK to always clear this field, because __go_can_recover will
only be called by a stub created for a function that calls recover.
That stub will not call a function created by reflect.MakeFunc, so
by the time we get here any caller higher up on the call stack no
longer needs the information. */
void
__go_makefunc_returning (void)
{
struct __go_defer_stack *d;
d = runtime_g ()->defer;
if (d != NULL)
d->__makefunc_can_recover = 0;
} }
/* This is only called when it is valid for the caller to recover the /* This is only called when it is valid for the caller to recover the

View File

@ -539,6 +539,7 @@ runtime_main(void* dummy __attribute__((unused)))
d.__arg = (void*)-1; d.__arg = (void*)-1;
d.__panic = g->panic; d.__panic = g->panic;
d.__retaddr = nil; d.__retaddr = nil;
d.__makefunc_can_recover = 0;
d.__frame = &frame; d.__frame = &frame;
g->defer = &d; g->defer = &d;