Skip to content

Commit a223989

Browse files
committed
No longer require arguments to be pinned in GCChecker
1 parent 095dfdd commit a223989

File tree

6 files changed

+110
-116
lines changed

6 files changed

+110
-116
lines changed

src/clangsa/GCChecker.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
// Assumptions for pinning:
4-
// * args need to be pinned
5-
// * JL_ROOTING_ARGUMENT and JL_ROOTED_ARGUMENT will propagate pinning state as well.
64
// * The checker may not consider alias for derived pointers in some cases.
75
// * if f(x) returns a derived pointer from x, a = f(x); b = f(x); PTR_PIN(a); The checker will NOT find b as pinned.
86
// * a = x->y; b = x->y; PTR_PIN(a); The checker will find b as pinned.
@@ -49,7 +47,7 @@ static const Stmt *getStmtForDiagnostics(const ExplodedNode *N)
4947
}
5048

5149
// Turn on/off the log here
52-
#define DEBUG_LOG 1
50+
#define DEBUG_LOG 0
5351

5452
class GCChecker
5553
: public Checker<
@@ -175,6 +173,9 @@ class GCChecker
175173
} else if (parent.isPinned()) {
176174
// If parent is pinned, the child is not pinned.
177175
return getNotPinned(parent);
176+
} else if (parent.isMoved()) {
177+
// If parent is moved, the child is not pinned.
178+
return getNotPinned(parent);
178179
} else {
179180
// For other cases, the children have the same state as the parent.
180181
return parent;
@@ -200,19 +201,20 @@ class GCChecker
200201
const ParmVarDecl *PVD) {
201202
bool isFunctionSafepoint = !isFDAnnotatedNotSafepoint(FD);
202203
bool maybeUnrooted = declHasAnnotation(PVD, "julia_maybe_unrooted");
203-
bool maybeUnpinned = declHasAnnotation(PVD, "julia_maybe_unpinned");
204-
if (!isFunctionSafepoint || maybeUnrooted || maybeUnpinned) {
204+
if (!isFunctionSafepoint || maybeUnrooted) {
205205
ValueState VS = getAllocated();
206206
VS.PVD = PVD;
207207
VS.FD = FD;
208208
return VS;
209209
}
210210
bool require_tpin = declHasAnnotation(PVD, "julia_require_tpin");
211+
bool require_pin = declHasAnnotation(PVD, "julia_require_pin");
211212
if (require_tpin) {
212213
return getRooted(nullptr, ValueState::TransitivelyPinned, -1);
213-
} else {
214-
// Assume arguments are pinned
214+
} else if (require_pin) {
215215
return getRooted(nullptr, ValueState::Pinned, -1);
216+
} else {
217+
return getRooted(nullptr, ValueState::NotPinned, -1);
216218
}
217219
}
218220
};
@@ -345,6 +347,7 @@ class GCChecker
345347
void validateValue(const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const;
346348
void validateValueRootnessOnly(const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const;
347349
void validateValue(const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const;
350+
void validateValueRootnessOnly(const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const;
348351
int validateValueInner(const GCChecker::ValueState* VS) const;
349352
GCChecker::ValueState getRootedFromRegion(const MemRegion *Region, const PinState *PS, int Depth) const;
350353
template <typename T>
@@ -481,6 +484,15 @@ static const VarRegion *walk_back_to_global_VR(const MemRegion *Region) {
481484
#define FREED 1
482485
#define MOVED 2
483486

487+
void GCChecker::validateValueRootnessOnly(const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const {
488+
int v = validateValueInner(VS);
489+
if (v == FREED) {
490+
GCChecker::report_value_error(C, Sym, (std::string(message) + " GCed").c_str(), range);
491+
} else if (v == MOVED) {
492+
// We don't care if it is moved
493+
}
494+
}
495+
484496
void GCChecker::validateValue(const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const {
485497
int v = validateValueInner(VS);
486498
if (v == FREED) {
@@ -1139,10 +1151,10 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call,
11391151
// Symbolically move all unpinned values.
11401152
GCValueMapTy AMap2 = State->get<GCValueMap>();
11411153
for (auto I = AMap2.begin(), E = AMap2.end(); I != E; ++I) {
1154+
logWithDump("- check Sym", I.getKey());
11421155
if (RetSym == I.getKey())
11431156
continue;
11441157
if (I.getData().isNotPinned()) {
1145-
logWithDump("- move unpinned values, Sym", I.getKey());
11461158
logWithDump("- move unpinned values, VS", I.getData());
11471159
auto NewVS = ValueState::getMoved(I.getData());
11481160
State = State->set<GCValueMap>(I.getKey(), NewVS);
@@ -1195,9 +1207,9 @@ bool GCChecker::processArgumentRooting(const CallEvent &Call, CheckerContext &C,
11951207
const ValueState *CurrentVState = State->get<GCValueMap>(RootedSymbol);
11961208
ValueState NewVState = *OldVState;
11971209
// If the old state is pinned, the new state is not pinned.
1198-
if (OldVState->isPinned() && ((CurrentVState && !CurrentVState->isPinnedByAnyway()) || !CurrentVState)) {
1199-
NewVState = ValueState::getNotPinned(*OldVState);
1200-
}
1210+
// if (OldVState->isPinned() && ((CurrentVState && !CurrentVState->isPinnedByAnyway()) || !CurrentVState)) {
1211+
// NewVState = ValueState::getNotPinned(*OldVState);
1212+
// }
12011213
logWithDump("- Rooted set to", NewVState);
12021214
State = State->set<GCValueMap>(RootedSymbol, NewVState);
12031215
return true;
@@ -1633,23 +1645,16 @@ void GCChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
16331645
range);
16341646
}
16351647
}
1636-
if (ValState->isNotPinned()) {
1637-
bool MaybeUnpinned = false;
1638-
if (FD) {
1639-
if (idx < FD->getNumParams()) {
1640-
MaybeUnpinned =
1641-
declHasAnnotation(FD->getParamDecl(idx), "julia_maybe_unpinned");
1642-
}
1643-
}
1644-
if (!MaybeUnpinned && isCalleeSafepoint) {
1645-
report_value_error(C, Sym, "Passing non-pinned value as argument to function that may GC", range);
1646-
}
1647-
}
16481648
if (FD && idx < FD->getNumParams() && declHasAnnotation(FD->getParamDecl(idx), "julia_require_tpin")) {
16491649
if (!ValState->isTransitivelyPinned()) {
16501650
report_value_error(C, Sym, "Passing non-tpinned argument to function that requires a tpin argument.");
16511651
}
16521652
}
1653+
if (FD && idx < FD->getNumParams() && declHasAnnotation(FD->getParamDecl(idx), "julia_require_pin")) {
1654+
if (!ValState->isPinnedByAnyway()) {
1655+
report_value_error(C, Sym, "Passing non-pinned argument to function that requires a pin argument.");
1656+
}
1657+
}
16531658
}
16541659
}
16551660

@@ -1810,6 +1815,7 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
18101815
}
18111816

18121817
const ValueState *OldVS = C.getState()->get<GCValueMap>(Sym);
1818+
logWithDump("- PTR_PIN OldVS", OldVS);
18131819
if (OldVS && OldVS->isMoved()) {
18141820
report_error(C, "Attempt to PIN a value that is already moved.");
18151821
return true;

src/julia.h

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,6 @@ extern void _JL_GC_PUSHARGS(jl_value_t **, size_t) JL_NOTSAFEPOINT;
915915

916916
extern void JL_GC_POP() JL_NOTSAFEPOINT;
917917

918-
#ifdef MMTK_GC
919918
extern void JL_GC_PUSH1_NO_TPIN(void *) JL_NOTSAFEPOINT;
920919
extern void JL_GC_PUSH2_NO_TPIN(void *, void *) JL_NOTSAFEPOINT;
921920
extern void JL_GC_PUSH3_NO_TPIN(void *, void *, void *) JL_NOTSAFEPOINT;
@@ -931,8 +930,6 @@ extern void _JL_GC_PUSHARGS_NO_TPIN(jl_value_t **, size_t) JL_NOTSAFEPOINT;
931930
memset(rts_var, 0, sizeof(void*) * (n)); \
932931
_JL_GC_PUSHARGS_NO_TPIN(rts_var, (n));
933932

934-
#endif
935-
936933
#else
937934

938935
#define JL_GC_PUSH1(arg1) \
@@ -976,9 +973,6 @@ extern void _JL_GC_PUSHARGS_NO_TPIN(jl_value_t **, size_t) JL_NOTSAFEPOINT;
976973

977974
#define JL_GC_POP() (jl_pgcstack = jl_pgcstack->prev)
978975

979-
#endif
980-
981-
#ifdef MMTK_GC
982976
// these are pinning roots: only the root object needs to be pinned as opposed to
983977
// the functions above which are transitively pinning
984978
#define JL_GC_PUSH1_NO_TPIN(arg1) \
@@ -1019,25 +1013,7 @@ extern void _JL_GC_PUSHARGS_NO_TPIN(jl_value_t **, size_t) JL_NOTSAFEPOINT;
10191013
((void**)rts_var)[-1] = jl_pgcstack; \
10201014
memset((void*)rts_var, 0, (n)*sizeof(jl_value_t*)); \
10211015
jl_pgcstack = (jl_gcframe_t*)&(((void**)rts_var)[-2])
1022-
#else
1023-
// When not using MMTk, default to the stock functions
1024-
#define JL_GC_PUSH1_NO_TPIN(arg1) JL_GC_PUSH1(arg1)
1025-
1026-
#define JL_GC_PUSH2_NO_TPIN(arg1, arg2) JL_GC_PUSH2(arg1, arg2)
1027-
1028-
#define JL_GC_PUSH3_NO_TPIN(arg1, arg2, arg3) JL_GC_PUSH3(arg1, arg2, arg3)
1029-
1030-
#define JL_GC_PUSH4_NO_TPIN(arg1, arg2, arg3, arg4) JL_GC_PUSH4(arg1, arg2, arg3, arg4)
1031-
1032-
#define JL_GC_PUSH5_NO_TPIN(arg1, arg2, arg3, arg4, arg5) JL_GC_PUSH5(arg1, arg2, arg3, arg4, arg5)
1033-
1034-
#define JL_GC_PUSH6_NO_TPIN(arg1, arg2, arg3, arg4, arg5, arg6) JL_GC_PUSH6(arg1, arg2, arg3, arg4, arg5, arg6)
1035-
1036-
#define JL_GC_PUSH7_NO_TPIN(arg1, arg2, arg3, arg4, arg5, arg6, arg7) JL_GC_PUSH7(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
1037-
1038-
#define JL_GC_PUSH8_NO_TPIN(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) JL_GC_PUSH8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
10391016

1040-
#define JL_GC_PUSHARGS_NO_TPIN(rts_var,n) JL_GC_PUSHARGS(rts_var,n)
10411017
#endif
10421018

10431019
JL_DLLEXPORT int jl_gc_enable(int on);
@@ -1871,12 +1847,12 @@ JL_DLLEXPORT void JL_NORETURN jl_exceptionf(jl_datatype_t *ty,
18711847
JL_DLLEXPORT void JL_NORETURN jl_too_few_args(const char *fname, int min);
18721848
JL_DLLEXPORT void JL_NORETURN jl_too_many_args(const char *fname, int max);
18731849
JL_DLLEXPORT void JL_NORETURN jl_type_error(const char *fname,
1874-
jl_value_t *expected JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED,
1875-
jl_value_t *got JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED);
1850+
jl_value_t *expected JL_MAYBE_UNROOTED,
1851+
jl_value_t *got JL_MAYBE_UNROOTED);
18761852
JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname,
18771853
const char *context,
1878-
jl_value_t *ty JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED,
1879-
jl_value_t *got JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED);
1854+
jl_value_t *ty JL_MAYBE_UNROOTED,
1855+
jl_value_t *got JL_MAYBE_UNROOTED);
18801856
JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var);
18811857
JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_sym_t *type_name, jl_sym_t *var);
18821858
JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str);

src/rtutils.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ JL_DLLEXPORT void JL_NORETURN jl_too_many_args(const char *fname, int max)
109109

110110
// with function name / location description, plus extra context
111111
JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, const char *context,
112-
jl_value_t *expected JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED,
113-
jl_value_t *got JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED)
112+
jl_value_t *expected JL_MAYBE_UNROOTED,
113+
jl_value_t *got JL_MAYBE_UNROOTED)
114114
{
115115
jl_value_t *ctxt=NULL;
116116
JL_GC_PUSH3(&ctxt, &expected, &got);
@@ -121,8 +121,8 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, const char *co
121121

122122
// with function name or description only
123123
JL_DLLEXPORT void JL_NORETURN jl_type_error(const char *fname,
124-
jl_value_t *expected JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED,
125-
jl_value_t *got JL_MAYBE_UNROOTED JL_MAYBE_UNPINNED)
124+
jl_value_t *expected JL_MAYBE_UNROOTED,
125+
jl_value_t *got JL_MAYBE_UNROOTED)
126126
{
127127
jl_type_error_rt(fname, "", expected, got);
128128
}

src/support/analyzer_annotations.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#define JL_PROPAGATES_ROOT __attribute__((annotate("julia_propagates_root")))
1414
#define JL_NOTSAFEPOINT __attribute__((annotate("julia_not_safepoint")))
1515
#define JL_MAYBE_UNROOTED __attribute__((annotate("julia_maybe_unrooted")))
16-
#define JL_MAYBE_UNPINNED __attribute__((annotate("julia_maybe_unpinned")))
1716
#define JL_GLOBALLY_ROOTED __attribute__((annotate("julia_globally_rooted")))
1817
#define JL_GLOBALLY_PINNED __attribute__((annotate("julia_globally_pinned")))
1918
#define JL_GLOBALLY_TPINNED __attribute__((annotate("julia_globally_tpinned")))
@@ -24,6 +23,7 @@
2423
#define JL_ROOTS_TEMPORARILY __attribute__((annotate("julia_temporarily_roots")))
2524
#define JL_REQUIRE_ROOTED_SLOT __attribute__((annotate("julia_require_rooted_slot")))
2625
#define JL_REQUIRE_TPIN __attribute__((annotate("julia_require_tpin")))
26+
#define JL_REQUIRE_PIN __attribute__((annotate("julia_require_pin")))
2727
#ifdef __cplusplus
2828
extern "C" {
2929
#endif
@@ -38,7 +38,6 @@ extern "C" {
3838
#define JL_PROPAGATES_ROOT
3939
#define JL_NOTSAFEPOINT
4040
#define JL_MAYBE_UNROOTED
41-
#define JL_MAYBE_UNPINNED
4241
// The runtime may mark any object that is reachable from a global root as globally rooted.
4342
// So JL_GLOBALLY_ROOTED does not need to an actual root. Thus we don't know anything
4443
// about pining state.
@@ -54,6 +53,7 @@ extern "C" {
5453
#define JL_ROOTS_TEMPORARILY
5554
#define JL_REQUIRE_ROOTED_SLOT
5655
#define JL_REQUIRE_TPIN
56+
#define JL_REQUIRE_PIN
5757
#define JL_GC_PROMISE_ROOTED(x) (void)(x)
5858
#define jl_may_leak(x) (void)(x)
5959

0 commit comments

Comments
 (0)