Skip to content
Open
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
63 changes: 60 additions & 3 deletions src/lgc.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static uint32_t trace_heaps = 0;
static int local_collection(lua_State *L, int type);
static int global_trace(lua_State *L);
static void unblock_mutators(lua_State *L);
static void validate_heap_objects(lua_State *L, const char *where);

static INLINE int is_black(lua_State *L, GCheader *obj)
{
Expand Down Expand Up @@ -1656,6 +1657,8 @@ void luaC_inherit_thread(lua_State *L, lua_State *th)
ck_sequence_write_end(&th->memlock);
luaE_flush_stringtable(th);

validate_heap_objects(L, "inherit_thread:before_transfer");

TAILQ_FOREACH_SAFE(steal, &th->heap->objects, allocd, tmp) {
/* Update owner before removing from source heap. This ensures that
* if any concurrent reader sees this object, it will either:
Expand All @@ -1670,6 +1673,9 @@ void luaC_inherit_thread(lua_State *L, lua_State *th)

make_grey(L, steal);
}

validate_heap_objects(L, "inherit_thread:after_transfer");

TAILQ_REMOVE(&G(L)->all_heaps, th->heap, heaps);
unlock_all_threads();

Expand Down Expand Up @@ -1954,6 +1960,44 @@ static void sanity_check_mark_status(lua_State *L)
}
}

static int is_bad_gc_ptr(uintptr_t p)
{
return p == 0x5a5a5a5a5a5a5a5aULL || p == 0 || (p & 0x7) != 0;
}

static void validate_heap_objects(lua_State *L, const char *where)
{
GCheader *o;
int count = 0;

TAILQ_FOREACH(o, &L->heap->objects, allocd) {
if (is_bad_gc_ptr((uintptr_t)o) ||
o->tt < LUA_TSTRING || o->tt > LUA_TGLOBAL ||
(o->marked & FREEDBIT)) {
if (!is_bad_gc_ptr((uintptr_t)o))
thrlua_log(L, DCRITICAL,
"thrlua HEAP CORRUPT [%s] L=%p heap=%p count=%d bad_node=%p"
" tt=%d marked=0x%x\n",
where, (void*)L, (void*)L->heap, count, (void*)o,
o->tt, o->marked);
else
thrlua_log(L, DCRITICAL,
"thrlua HEAP CORRUPT [%s] L=%p heap=%p count=%d bad_node=%p\n",
where, (void*)L, (void*)L->heap, count, (void*)o);
abort();
}
if (o->owner != L->heap) {
thrlua_log(L, DCRITICAL,
"thrlua HEAP CORRUPT [%s] L=%p heap=%p count=%d node=%p"
" owner=%p (expected %p) tt=%d\n",
where, (void*)L, (void*)L->heap, count, (void*)o,
(void*)o->owner, (void*)L->heap, o->tt);
abort();
}
count++;
}
}

static int local_collection(lua_State *L, int type)
{
int reclaimed;
Expand All @@ -1974,6 +2018,8 @@ static int local_collection(lua_State *L, int type)
* while we are in this function and manipulating our string tables or heap */
block_collector(L, pt);

validate_heap_objects(L, "local_collection:entry");

/* prune out excess string table entries.
* We don't want to be too aggressive, as we'd like to see some benefit
* from string interning. We remove the head of each chain and repeat
Expand Down Expand Up @@ -2020,6 +2066,8 @@ static int local_collection(lua_State *L, int type)
check_references(L);
}

validate_heap_objects(L, "local_collection:after_mark");

/* run any finalizers; may turn some objects grey again */
run_finalize(L);

Expand All @@ -2035,26 +2083,34 @@ static int local_collection(lua_State *L, int type)
/* remove collected weak values from weak tables */
fixup_weak_refs(L);

validate_heap_objects(L, "local_collection:before_reclaim");

/* and now we can free whatever is left in White. Note that we're still
* blocked here so we are pulling white out of the heap and placing them
* in another list that will free them when we unblock the collector. */
reclaimed = reclaim_white(L, 0);

validate_heap_objects(L, "local_collection:after_reclaim");

/* White is the new Black */
L->black = !L->black;

sanity_check_mark_status(L);

/* Finalize deferred objects */
finalize_deferred(L);

validate_heap_objects(L, "local_collection:after_finalize");

/* Now we can un-block the global collector, as we are done with our string
* tables and our heap. */
unblock_collector(L, pt);

/* Finalize deferred objects */
finalize_deferred(L);

/* Free any objects that were white */
free_deferred_white(L);

validate_heap_objects(L, "local_collection:after_free");

/* Free any deferred stringtable nodes */
while (tofree) {
n = tofree;
Expand Down Expand Up @@ -2119,6 +2175,7 @@ static void trace_heap(GCheap *h)
GCheader *o;

ck_pr_store_32(&h->owner->xref_count, 0);
validate_heap_objects(h->owner, "trace_heap");
TAILQ_FOREACH(o, &h->objects, allocd) {
global_trace_obj(h->owner, &h->owner->gch, o);
}
Expand Down