Fix regression in _gclongjmp()

This commit is contained in:
Justine Tunney 2021-08-19 08:30:00 -07:00
parent da45c7c80b
commit 65f32fad52
12 changed files with 225 additions and 25 deletions

39
libc/log/getsymbol.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/bisectcarleft.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/**
* Returns name of symbol at address.
*/
char *GetSymbolByAddr(int64_t addr) {
struct SymbolTable *st;
if ((st = GetSymbolTable()) && st->count &&
((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end)) {
return st->name_base +
st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base)]
.name_rva;
} else {
return 0;
}
}

View file

@ -55,6 +55,9 @@ bool32 IsDebuggerPresent(bool);
bool IsRunningUnderMake(void);
const char *GetSiCodeName(int, int);
void AppendResourceReport(char **, struct rusage *, const char *);
char *GetSymbolByAddr(int64_t);
void PrintGarbage(FILE *);
void PrintGarbageNumeric(FILE *);
#define showcrashreports() ShowCrashReports()

42
libc/log/printgarbage.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h"
/* clang-format off */
/**
* Prints list of deferred operations on shadow stack.
*/
void PrintGarbage(FILE *f) {
size_t i;
f = stderr;
fprintf(f, "\n");
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0));
fprintf(f, " garbage entry parent frame original ret callback arg \n");
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n");
for (i = __garbage.i; i--;) {
fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
GetSymbolByAddr(__garbage.p[i].ret-1),
GetSymbolByAddr(__garbage.p[i].fn),
__garbage.p[i].arg);
}
}

View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h"
/* clang-format off */
/**
* Prints list of deferred operations on shadow stack w/o symbols.
*/
void PrintGarbageNumeric(FILE *f) {
size_t i;
f = stderr;
fprintf(f, "\n");
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0));
fprintf(f, " garbage entry parent frame original ret callback arg \n");
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n");
for (i = __garbage.i; i--;) {
fprintf(f, "0x%012lx 0x%012lx 0x%016lx 0x%016lx 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
__garbage.p[i].ret,
__garbage.p[i].fn,
__garbage.p[i].arg);
}
}

View file

@ -42,7 +42,7 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) {
__garbage.p = p2;
__garbage.n = n2;
}
__garbage.p[__garbage.i].frame = frame->next;
__garbage.p[__garbage.i].frame = frame;
__garbage.p[__garbage.i].fn = (intptr_t)fn;
__garbage.p[__garbage.i].arg = (intptr_t)arg;
__garbage.p[__garbage.i].ret = frame->addr;

View file

@ -19,6 +19,7 @@
#include "libc/macros.internal.h"
#include "libc/dce.h"
#include "libc/notice.inc"
#define INITIAL_CAPACITY 4
// Invokes deferred function calls.
@ -44,19 +45,17 @@ __gc: decq __garbage(%rip)
// </LIMBO>
push %rbp
mov %rsp,%rbp
sub $0x20,%rsp
sub $16,%rsp
push %rax
push %rdx
movdqa %xmm0,-0x20(%rbp)
movdqa %xmm1,-0x10(%rbp)
movdqa %xmm0,-16(%rbp)
call *%r9
movdqa -0x10(%rbp),%xmm1
movdqa -0x20(%rbp),%xmm0
movdqa -16(%rbp),%xmm0
pop %rdx
pop %rax
leave
ret
9: call abort
9: hlt
.endfn __gc,globl,hidden
.source __FILE__

View file

@ -30,29 +30,27 @@
// @see examples/ctrlc.c
// @noreturn
_gclongjmp:
.leafprologue
push %rbp
mov %rsp,%rbp
.profilable
.weak __garbage
lea __garbage(%rip),%r12
test %r12,%r12
mov (%r12),%r13 # garbage.i
test %r13,%r13
jnz .L.unwind.destructors
0: jmp longjmp
.L.unwind.destructors:
push %rdi
push %rsi
mov (%r12),%r13 # garbage.i
mov 16(%r12),%r14 # garbage.p
mov (%rdi),%r15 # jmp_buf[0] is new %rsp
shl $5,%r13
1: test %r13,%r13
jz 2f
sub $32,%r13
cmp (%r14,%r13),%r15
ja 2f
mov 8(%r14,%r13),%rax # garbage.p[𝑖].fn
shl $5,%r13 # log2(sizeof(struct Garbage))
1: sub $32,%r13 # 𝑖--
js 2f
cmp (%r14,%r13),%r15 # new %rsp > garbage.p[𝑖].frame
jbe 2f
mov 16(%r14,%r13),%rdi # garbage.p[𝑖].arg
call *%rax
decq (%r12)
callq *8(%r14,%r13) # garbage.p[𝑖].fn
decq (%r12) # garbage.i--
jmp 1b
2: pop %rsi
pop %rdi

View file

@ -27,7 +27,8 @@
// @assume system five nexgen32e abi conformant
// @note code built w/ microsoft abi compiler can't call this
// @see _gclongjmp() unwinds _gc() destructors
longjmp:mov %esi,%eax
longjmp:
mov %esi,%eax
test %eax,%eax
jnz 1f
inc %eax

View file

@ -3,8 +3,9 @@
#include "libc/runtime/gc.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define gc(THING) _gc(THING)
#define defer(FN, ARG) _defer(FN, ARG)
#define gc(THING) _gc(THING)
#define defer(FN, ARG) _defer(FN, ARG)
#define gclongjmp(JB, ARG) _gclongjmp(JB, ARG)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_INTERNAL_H_ */

View file

@ -0,0 +1,75 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#undef _gc
#define _gc(x) _defer(Free, x)
char *x;
char *y;
char *z;
jmp_buf jb;
void Free(char *p) {
strcpy(p, "FREE");
}
void C(void) {
x = _gc(strdup("abcd"));
if (0) PrintGarbage(stderr);
_gclongjmp(jb, 1);
abort();
}
void B(void C(void)) {
y = _gc(strdup("HIHI"));
C();
abort();
}
void A(void C(void), void B(void(void))) {
z = _gc(strdup("yoyo"));
B(C);
abort();
}
void (*Ap)(void(void), void(void(void))) = A;
void (*Bp)(void(void)) = B;
void (*Cp)(void) = C;
TEST(gclongjmp, test) {
if (!setjmp(jb)) {
Ap(Cp, Bp);
abort();
}
EXPECT_STREQ("FREE", x);
EXPECT_STREQ("FREE", y);
EXPECT_STREQ("FREE", z);
free(z);
free(y);
free(x);
}

View file

@ -1238,7 +1238,7 @@ static int panicback (lua_State *L) {
b = (struct Aux *)lua_touserdata(L, -1);
lua_pop(L, 1); /* remove 'Aux' struct */
runC(b->L, L, b->paniccode); /* run optional panic code */
longjmp(b->jb, 1);
_gclongjmp(b->jb, 1);
return 1; /* to avoid warnings */
}

View file

@ -646,7 +646,7 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
int status, result;
lua_State *L;
if (IsModeDbg()) ShowCrashReports();
/* if (IsModeDbg()) ShowCrashReports(); */
L = luaL_newstate(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");