Skip to content

Commit

Permalink
JL_GLOBALLY_ROOTED does not imply pinning. Add
Browse files Browse the repository at this point in the history
JL_GLOBALLY_PINNED/TPINNED
  • Loading branch information
qinsoon committed May 16, 2024
1 parent 5297a62 commit acf3a25
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 13 deletions.
41 changes: 32 additions & 9 deletions src/clangsa/GCChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

// Assumptions for pinning:
// * args need to be pinned
// * JL_ROOTING_ARGUMENT and JL_ROOTED_ARGUMENT will propogate pinning state as well.
// * globally rooted means pinned as well (not T pin).
// * JL_ROOTING_ARGUMENT and JL_ROOTED_ARGUMENT will propagate pinning state as well.

#include "clang/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
Expand Down Expand Up @@ -43,7 +42,7 @@ static const Stmt *getStmtForDiagnostics(const ExplodedNode *N)
}

// Turn on/off the log here
#define DEBUG_LOG 0
#define DEBUG_LOG 1

class GCChecker
: public Checker<
Expand Down Expand Up @@ -154,6 +153,19 @@ class GCChecker
else
return Pinned;
}
// Inherit state from a parent object to its child object
static ValueState inheritState(ValueState parent) {
if (parent.isTransitivelyPinned()) {
// If parent is tpinned, the child is tpinned.
return parent;
} else if (parent.isPinned()) {
// If parent is pinned, the child is not pinned.
return getNotPinned(parent);
} else {
// For other cases, the children have the same state as the parent.
return parent;
}
}

static ValueState getAllocated() {
return ValueState(Allocated, NotPinned, nullptr, -1);
Expand Down Expand Up @@ -1174,11 +1186,18 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
const FunctionDecl *FD = Decl ? Decl->getAsFunction() : nullptr;
if (FD) {
if (declHasAnnotation(FD, "julia_globally_rooted")) {
// Globally rooted = at least pinned
NewVState = ValueState::getRooted(nullptr, ValueState::Pinned, -1);
if (declHasAnnotation(FD, "julia_globally_pinned")) {
NewVState = ValueState::getRooted(nullptr, ValueState::Pinned, -1);
} else if (declHasAnnotation(FD, "julia_globally_tpinned")) {
NewVState = ValueState::getRooted(nullptr, ValueState::TransitivelyPinned, -1);
} else {
// Not pinned
NewVState = ValueState::getRooted(nullptr, -1);
}
} else {
// Special case for jl_box_ functions which have value-dependent
// global roots.
// See jl_as_global_root().
StringRef FDName =
FD->getDeclName().isIdentifier() ? FD->getName() : "";
if (FDName.startswith("jl_box_") || FDName.startswith("ijl_box_")) {
Expand All @@ -1197,6 +1216,7 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
}
}
if (GloballyRooted) {
// These are perm allocated, thus pinned.
NewVState = ValueState::getRooted(nullptr, ValueState::Pinned, -1);
}
}
Expand Down Expand Up @@ -1939,14 +1959,17 @@ bool GCChecker::rootRegionIfGlobal(const MemRegion *R, ProgramStateRef &State,
isGloballyRootedType(VD->getType())) {
State = State->set<GCRootMap>(R, RootState::getRoot(-1));
logWithDump("- rootRegionIfGlobal: root global", R);
if (isGloballyTransitivelyPinnedType(VD->getType())) {
if (isGloballyTransitivelyPinnedType(VD->getType()) || declHasAnnotation(VD, "julia_globally_tpinned")) {
State = State->set<GCPinMap>(R, PinState::getTransitivePin(-1));
logWithDump("- rootRegionIfGlobal: transitively pin global", R);
pinState = ValueState::TransitivelyPinned;
} else {
} else if (declHasAnnotation(VD, "julia_globally_pinned")) {
State = State->set<GCPinMap>(R, PinState::getPin(-1));
logWithDump("- rootRegionIfGlobal: pin global", R);
pinState = ValueState::Pinned;
} else {
logWithDump("- rootRegionIfGlobal: not pin", R);
pinState = ValueState::NotPinned;
}
isGlobalRoot = true;
}
Expand All @@ -1955,8 +1978,8 @@ bool GCChecker::rootRegionIfGlobal(const MemRegion *R, ProgramStateRef &State,
ValueState TheValS(isGlobalRoot ? ValueState::getRooted(R, pinState, -1)
: ValueState::getAllocated());
if (ValS) {
*ValS = TheValS;
logWithDump("- rootRegionIfGlobal: set ValS", TheValS);
*ValS = ValueState::inheritState(TheValS);
logWithDump("- rootRegionIfGlobal: inherit state", TheValS);
}
if (Sym) {
const ValueState *GVState = C.getState()->get<GCValueMap>(Sym);
Expand Down
9 changes: 9 additions & 0 deletions src/support/analyzer_annotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define JL_MAYBE_UNROOTED __attribute__((annotate("julia_maybe_unrooted")))
#define JL_MAYBE_UNPINNED __attribute__((annotate("julia_maybe_unpinned")))
#define JL_GLOBALLY_ROOTED __attribute__((annotate("julia_globally_rooted")))
#define JL_GLOBALLY_PINNED __attribute__((annotate("julia_globally_pinned")))
#define JL_GLOBALLY_TPINNED __attribute__((annotate("julia_globally_tpinned")))
#define JL_ROOTING_ARGUMENT __attribute__((annotate("julia_rooting_argument")))
#define JL_ROOTED_ARGUMENT __attribute__((annotate("julia_rooted_argument")))
#define JL_GC_DISABLED __attribute__((annotate("julia_gc_disabled")))
Expand All @@ -36,7 +38,14 @@ extern "C" {
#define JL_NOTSAFEPOINT
#define JL_MAYBE_UNROOTED
#define JL_MAYBE_UNPINNED
// The runtime may mark any object that is reachable from a global root as globally rooted.
// So JL_GLOBALLY_ROOTED does not need to an actual root. Thus we don't know anything
// about pining state.
#define JL_GLOBALLY_ROOTED
// A root may be pinned. But any object reachable from the root is not pinned.
#define JL_GLOBALLY_PINNED
// A root may be transitively pinned, and any object reachable from the root is transitively pinned.
#define JL_GLOBALLY_TPINNED
#define JL_ROOTING_ARGUMENT
#define JL_ROOTED_ARGUMENT
#define JL_GC_DISABLED
Expand Down
8 changes: 4 additions & 4 deletions test/clangsa/MissingRoots.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ int unrooted() {
// expected-note@-1{{Trying to access value which may have been GCed}}
}

extern jl_value_t *global_value JL_GLOBALLY_ROOTED;
extern jl_value_t *global_value JL_GLOBALLY_ROOTED JL_GLOBALLY_PINNED;
void globally_rooted() {
jl_value_t *val = global_value;
jl_gc_safepoint();
Expand Down Expand Up @@ -239,7 +239,7 @@ void pushargs_as_args()
JL_GC_POP();
}

static jl_typemap_entry_t *this_call_cache[10] JL_GLOBALLY_ROOTED;
static jl_typemap_entry_t *this_call_cache[10] JL_GLOBALLY_ROOTED JL_GLOBALLY_TPINNED;
void global_array2() {
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
Expand Down Expand Up @@ -296,12 +296,12 @@ void tparam0(jl_value_t *atype) {
look_at_value(jl_tparam0(atype));
}

extern jl_value_t *global_atype JL_GLOBALLY_ROOTED;
extern jl_value_t *global_atype JL_GLOBALLY_ROOTED JL_GLOBALLY_TPINNED;
void tparam0_global() {
look_at_value(jl_tparam0(global_atype));
}

static jl_value_t *some_global JL_GLOBALLY_ROOTED;
static jl_value_t *some_global JL_GLOBALLY_ROOTED JL_GLOBALLY_PINNED;
void global_copy() {
jl_value_t *local = NULL;
jl_gc_safepoint();
Expand Down

0 comments on commit acf3a25

Please sign in to comment.