Skip to content

Commit a8be283

Browse files
authored
[clangsa] write a checker for implicit seq_cst atomics (#42323)
and ensure we are using relaxed for single-threaded reader/writer
1 parent 162191c commit a8be283

24 files changed

+431
-99
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ all: debug release
99
# sort is used to remove potential duplicates
1010
DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir))
1111
ifneq ($(BUILDROOT),$(JULIAHOME))
12-
BUILDDIRS := $(BUILDROOT) $(addprefix $(BUILDROOT)/,base src src/flisp src/support src/clangsa cli doc deps stdlib test test/embedding test/llvmpasses)
12+
BUILDDIRS := $(BUILDROOT) $(addprefix $(BUILDROOT)/,base src src/flisp src/support src/clangsa cli doc deps stdlib test test/clangsa test/embedding test/llvmpasses)
1313
BUILDDIRMAKE := $(addsuffix /Makefile,$(BUILDDIRS)) $(BUILDROOT)/sysimage.mk
1414
DIRS := $(DIRS) $(BUILDDIRS)
1515
$(BUILDDIRMAKE): | $(BUILDDIRS)

src/Makefile

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ clean-support:
355355

356356
cleanall: clean clean-flisp clean-support clean-analyzegc
357357

358-
$(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT): $(SRCDIR)/clangsa/GCChecker.cpp $(LLVM_CONFIG_ABSOLUTE)
358+
$(build_shlibdir)/lib%Plugin.$(SHLIB_EXT): $(SRCDIR)/clangsa/%.cpp $(LLVM_CONFIG_ABSOLUTE)
359359
@$(call PRINT_CC, $(CXX) -g $(fPIC) -shared -o $@ -DCLANG_PLUGIN -I$(build_includedir) -L$(build_libdir) \
360360
$(LLVM_CXXFLAGS) $(CLANG_LDFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(CXXLDFLAGS) $<)
361361

@@ -374,26 +374,36 @@ ifneq ($(BUILD_LLVM_CLANG),1)
374374
endif
375375
endif
376376

377-
clangsa: $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT)
377+
clangsa: $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT)
378378

379379
clang-sagc-%: $(SRCDIR)/%.c $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check
380-
@$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c $<)
380+
@$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text --analyzer-no-default-checks \
381+
-Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker \
382+
$(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -fcolor-diagnostics -Werror -x c $<)
381383
clang-sagc-%: $(SRCDIR)/%.cpp $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check
382-
@$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c++ $<)
384+
@$(call PRINT_ANALYZE, $(build_bindir)/clang -D__clang_gcanalyzer__ --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text --analyzer-no-default-checks \
385+
-Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker \
386+
$(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) -fcolor-diagnostics -Werror -x c++ $<)
383387

384388
# optarg is a required_argument for these
385389
SA_EXCEPTIONS-jloptions.c := -Xanalyzer -analyzer-disable-checker=core.NonNullParamChecker,unix.cstring.NullArg
386390
# clang doesn't understand that e->vars has the same value in save_env (NULL) and restore_env (assumed non-NULL)
387391
SA_EXCEPTIONS-subtype.c := -Xanalyzer -analyzer-disable-checker=core.uninitialized.Assign,core.UndefinedBinaryOperatorResult
392+
# these need to be annotated (and possibly fixed)
393+
SKIP_IMPLICIT_ATOMICS := dump.c gf.c jitlayers.cpp module.c precompile.c rtutils.c staticdata.c toplevel.c codegen.cpp
388394

389-
clang-sa-%: $(SRCDIR)/%.c .FORCE | analyzegc-deps-check
395+
clang-sa-%: $(SRCDIR)/%.c $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check
390396
@$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text \
397+
$(if $(findstring $(notdir $<),$(SKIP_IMPLICIT_ATOMICS)),,-Xclang -load -Xclang $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT) -Xclang -analyzer-checker=julia.ImplicitAtomics) \
391398
-Xanalyzer -analyzer-disable-checker=deadcode.DeadStores \
399+
--analyzer-no-default-checks \
392400
$(SA_EXCEPTIONS-$(notdir $<)) \
393401
$(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -fcolor-diagnostics -Werror -x c $<)
394-
clang-sa-%: $(SRCDIR)/%.cpp .FORCE | analyzegc-deps-check
402+
clang-sa-%: $(SRCDIR)/%.cpp $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT) .FORCE | analyzegc-deps-check
395403
@$(call PRINT_ANALYZE, $(build_bindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text \
404+
$(if $(findstring $(notdir $<),$(SKIP_IMPLICIT_ATOMICS)),,-Xclang -load -Xclang $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT) -Xclang -analyzer-checker=julia.ImplicitAtomics) \
396405
-Xanalyzer -analyzer-disable-checker=deadcode.DeadStores \
406+
--analyzer-no-default-checks \
397407
$(SA_EXCEPTIONS-$(notdir $<)) \
398408
$(CLANGSA_FLAGS) $(CLANGSA_CXXFLAGS) $(LLVM_CXXFLAGS) $(JCPPFLAGS) $(JCXXFLAGS) $(DEBUGFLAGS) -fcolor-diagnostics -Werror -x c++ $<)
399409

@@ -404,6 +414,7 @@ analyzegc: analyzesrc $(addprefix clang-sagc-,$(RUNTIME_SRCS))
404414

405415
clean-analyzegc:
406416
rm -f $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT)
417+
rm -f $(build_shlibdir)/libImplicitAtomicsPlugin.$(SHLIB_EXT)
407418

408419
.FORCE:
409420
.PHONY: default all debug release clean cleanall clean-* libccalltest libllvmcalltest julia_flisp.boot.inc.phony analyzegc analyzesrc .FORCE

src/builtins.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1761,7 +1761,9 @@ static void add_builtin(const char *name, jl_value_t *v)
17611761
jl_fptr_args_t jl_get_builtin_fptr(jl_value_t *b)
17621762
{
17631763
assert(jl_isa(b, (jl_value_t*)jl_builtin_type));
1764-
return ((jl_typemap_entry_t*)jl_gf_mtable(b)->cache)->func.linfo->cache->specptr.fptr1;
1764+
jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_atomic_load_relaxed(&jl_gf_mtable(b)->cache);
1765+
jl_code_instance_t *ci = jl_atomic_load_relaxed(&entry->func.linfo->cache);
1766+
return jl_atomic_load_relaxed(&ci->specptr.fptr1);
17651767
}
17661768

17671769
static jl_value_t *add_builtin_func(const char *name, jl_fptr_args_t fptr)

src/clangsa/ImplicitAtomics.cpp

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
//===-- ImplicitAtomicsChecker.cpp - Null dereference checker -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This defines NullDerefChecker, a builtin check in ExprEngine that performs
10+
// checks for null pointers at loads and stores.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "clang/AST/ExprObjC.h"
15+
#include "clang/AST/ExprOpenMP.h"
16+
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17+
#include "clang/StaticAnalyzer/Core/Checker.h"
18+
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19+
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
21+
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
22+
#include "llvm/ADT/SmallString.h"
23+
#include "llvm/Support/raw_ostream.h"
24+
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
25+
26+
27+
using namespace clang;
28+
using namespace ento;
29+
30+
namespace {
31+
class ImplicitAtomicsChecker
32+
: public Checker< check::PreStmt<CastExpr>,
33+
check::PreStmt<BinaryOperator>,
34+
check::PreStmt<UnaryOperator>,
35+
check::PreCall> {
36+
//check::Bind
37+
//check::Location
38+
BugType ImplicitAtomicsBugType{this, "Implicit Atomic seq_cst synchronization", "Atomics"};
39+
40+
void reportBug(const Stmt *S, CheckerContext &C) const;
41+
void reportBug(const Stmt *S, CheckerContext &C, StringRef desc) const;
42+
void reportBug(const CallEvent &S, CheckerContext &C, StringRef desc="") const;
43+
44+
public:
45+
//void checkLocation(SVal location, bool isLoad, const Stmt* S,
46+
// CheckerContext &C) const;
47+
//void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
48+
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
49+
void checkPreStmt(const UnaryOperator *UOp, CheckerContext &C) const;
50+
void checkPreStmt(const BinaryOperator *BOp, CheckerContext &C) const;
51+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
52+
};
53+
} // end anonymous namespace
54+
55+
// Checks if RD has name in Names and is in std namespace
56+
static bool hasStdClassWithName(const CXXRecordDecl *RD,
57+
ArrayRef<llvm::StringLiteral> Names) {
58+
// or could check ASTContext::getQualifiedTemplateName()->isDerivedFrom() ?
59+
if (!RD || !RD->getDeclContext()->isStdNamespace())
60+
return false;
61+
if (RD->getDeclName().isIdentifier()) {
62+
StringRef Name = RD->getName();
63+
return llvm::any_of(Names, [&Name](StringRef GivenName) -> bool {
64+
return Name == GivenName;
65+
});
66+
}
67+
return false;
68+
}
69+
70+
constexpr llvm::StringLiteral STD_PTR_NAMES[] = {"atomic", "atomic_ref"};
71+
72+
static bool isStdAtomic(const CXXRecordDecl *RD) {
73+
return hasStdClassWithName(RD, STD_PTR_NAMES);
74+
}
75+
76+
static bool isStdAtomicCall(const Expr *E) {
77+
return E && isStdAtomic(E->IgnoreImplicit()->getType()->getAsCXXRecordDecl());
78+
}
79+
80+
static bool isStdAtomic(const Expr *E) {
81+
return E->getType()->isAtomicType();
82+
}
83+
84+
void ImplicitAtomicsChecker::reportBug(const CallEvent &S, CheckerContext &C, StringRef desc) const {
85+
reportBug(S.getOriginExpr(), C, desc);
86+
}
87+
88+
// try to find the "best" node to attach this to, so we generate fewer duplicate reports
89+
void ImplicitAtomicsChecker::reportBug(const Stmt *S, CheckerContext &C) const {
90+
while (1) {
91+
const auto *expr = dyn_cast<Expr>(S);
92+
if (!expr)
93+
break;
94+
expr = expr->IgnoreParenCasts();
95+
if (const auto *UO = dyn_cast<UnaryOperator>(expr))
96+
S = UO->getSubExpr();
97+
else if (const auto *BO = dyn_cast<BinaryOperator>(expr))
98+
S = isStdAtomic(BO->getLHS()) ? BO->getLHS() :
99+
isStdAtomic(BO->getRHS()) ? BO->getRHS() :
100+
BO->getLHS();
101+
else
102+
break;
103+
}
104+
reportBug(S, C, "");
105+
}
106+
107+
void ImplicitAtomicsChecker::reportBug(const Stmt *S, CheckerContext &C, StringRef desc) const {
108+
SmallString<100> buf;
109+
llvm::raw_svector_ostream os(buf);
110+
os << ImplicitAtomicsBugType.getDescription() << desc;
111+
PathDiagnosticLocation N = PathDiagnosticLocation::createBegin(
112+
S, C.getSourceManager(), C.getLocationContext());
113+
auto report = std::make_unique<BasicBugReport>(ImplicitAtomicsBugType, buf.str(), N);
114+
C.emitReport(std::move(report));
115+
}
116+
117+
void ImplicitAtomicsChecker::checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
118+
//if (isStdAtomic(CE) != isStdAtomic(CE->getSubExpr())) { // AtomicToNonAtomic or NonAtomicToAtomic CastExpr
119+
if (CE->getCastKind() == CK_AtomicToNonAtomic) {
120+
reportBug(CE, C);
121+
}
122+
}
123+
124+
void ImplicitAtomicsChecker::checkPreStmt(const UnaryOperator *UOp,
125+
CheckerContext &C) const {
126+
if (UOp->getOpcode() == UO_AddrOf)
127+
return;
128+
const Expr *Sub = UOp->getSubExpr();
129+
if (isStdAtomic(UOp) || isStdAtomic(Sub))
130+
reportBug(UOp, C);
131+
}
132+
133+
void ImplicitAtomicsChecker::checkPreStmt(const BinaryOperator *BOp,
134+
CheckerContext &C) const {
135+
const Expr *Lhs = BOp->getLHS();
136+
const Expr *Rhs = BOp->getRHS();
137+
if (isStdAtomic(Lhs) || isStdAtomic(Rhs) || isStdAtomic(BOp))
138+
reportBug(BOp, C);
139+
}
140+
141+
void ImplicitAtomicsChecker::checkPreCall(const CallEvent &Call,
142+
CheckerContext &C) const {
143+
const auto *MC = dyn_cast<CXXInstanceCall>(&Call);
144+
if (!MC || !isStdAtomicCall(MC->getCXXThisExpr()))
145+
return;
146+
if (const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call)) {
147+
OverloadedOperatorKind OOK = OC->getOverloadedOperator();
148+
if (CXXOperatorCallExpr::isAssignmentOp(OOK) || OOK == OO_PlusPlus || OOK == OO_MinusMinus) {
149+
reportBug(Call, C, " (std::atomic)");
150+
}
151+
}
152+
else if (const auto *Convert = dyn_cast<CXXConversionDecl>(MC->getDecl())) {
153+
reportBug(Call, C, " (std::atomic)");
154+
}
155+
}
156+
157+
158+
//// These seem probably unnecessary:
159+
//
160+
//static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false) {
161+
// const Expr *E = nullptr;
162+
//
163+
// // Walk through lvalue casts to get the original expression
164+
// // that syntactically caused the load.
165+
// if (const Expr *expr = dyn_cast<Expr>(S))
166+
// E = expr->IgnoreParenLValueCasts();
167+
//
168+
// if (IsBind) {
169+
// const VarDecl *VD;
170+
// const Expr *Init;
171+
// std::tie(VD, Init) = parseAssignment(S);
172+
// if (VD && Init)
173+
// E = Init;
174+
// }
175+
// return E;
176+
//}
177+
//
178+
//// load or bare symbol
179+
//void ImplicitAtomicsChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
180+
// CheckerContext &C) const {
181+
// const Expr *expr = getDereferenceExpr(S);
182+
// assert(expr);
183+
// if (isStdAtomic(expr))
184+
// reportBug(S, C);
185+
//}
186+
//
187+
//// auto &r = *l, or store
188+
//void ImplicitAtomicsChecker::checkBind(SVal L, SVal V, const Stmt *S,
189+
// CheckerContext &C) const {
190+
// const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
191+
// assert(expr);
192+
// if (isStdAtomic(expr))
193+
// reportBug(S, C, " (bind)");
194+
//}
195+
196+
namespace clang {
197+
namespace ento {
198+
void registerImplicitAtomicsChecker(CheckerManager &mgr) {
199+
mgr.registerChecker<ImplicitAtomicsChecker>();
200+
}
201+
bool shouldRegisterImplicitAtomicsChecker(const CheckerManager &mgr) {
202+
return true;
203+
}
204+
} // namespace ento
205+
} // namespace clang
206+
207+
#ifdef CLANG_PLUGIN
208+
extern "C" const char clang_analyzerAPIVersionString[] =
209+
CLANG_ANALYZER_API_VERSION_STRING;
210+
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
211+
registry.addChecker<ImplicitAtomicsChecker>(
212+
"julia.ImplicitAtomics", "Flags implicit atomic operations", ""
213+
);
214+
}
215+
#endif

src/dlload.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
202202
*/
203203
if (!abspath && jl_base_module != NULL) {
204204
jl_binding_t *b = jl_get_module_binding(jl_base_module, jl_symbol("DL_LOAD_PATH"));
205-
jl_array_t *DL_LOAD_PATH = (jl_array_t*)(b ? b->value : NULL);
205+
jl_array_t *DL_LOAD_PATH = (jl_array_t*)(b ? jl_atomic_load_relaxed(&b->value) : NULL);
206206
if (DL_LOAD_PATH != NULL) {
207207
size_t j;
208208
for (j = 0; j < jl_array_len(DL_LOAD_PATH); j++) {

src/gc.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ JL_DLLEXPORT void jl_finalize_th(jl_task_t *ct, jl_value_t *o)
537537
// still holding a reference to the object
538538
for (int i = 0; i < jl_n_threads; i++) {
539539
jl_ptls_t ptls2 = jl_all_tls_states[i];
540-
finalize_object(&ptls2->finalizers, o, &copied_list, ct->tid != i);
540+
finalize_object(&ptls2->finalizers, o, &copied_list, jl_atomic_load_relaxed(&ct->tid) != i);
541541
}
542542
finalize_object(&finalizer_list_marked, o, &copied_list, 0);
543543
if (copied_list.len > 0) {
@@ -2648,9 +2648,10 @@ mark: {
26482648
void *stkbuf = ta->stkbuf;
26492649
if (gc_cblist_task_scanner) {
26502650
export_gc_state(ptls, &sp);
2651+
int16_t tid = jl_atomic_load_relaxed(&ta->tid);
26512652
gc_invoke_callbacks(jl_gc_cb_task_scanner_t,
26522653
gc_cblist_task_scanner,
2653-
(ta, ta->tid != -1 && ta == jl_all_tls_states[ta->tid]->root_task));
2654+
(ta, tid != -1 && ta == jl_all_tls_states[tid]->root_task));
26542655
import_gc_state(ptls, &sp);
26552656
}
26562657
#ifdef COPY_STACKS
@@ -2664,8 +2665,9 @@ mark: {
26642665
uintptr_t ub = (uintptr_t)-1;
26652666
#ifdef COPY_STACKS
26662667
if (stkbuf && ta->copy_stack && ta->ptls == NULL) {
2667-
assert(ta->tid >= 0);
2668-
jl_ptls_t ptls2 = jl_all_tls_states[ta->tid];
2668+
int16_t tid = jl_atomic_load_relaxed(&ta->tid);
2669+
assert(tid >= 0);
2670+
jl_ptls_t ptls2 = jl_all_tls_states[tid];
26692671
ub = (uintptr_t)ptls2->stackbase;
26702672
lb = ub - ta->copy_stack;
26712673
offset = (uintptr_t)stkbuf - lb;

src/init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ static void post_boot_hooks(void)
854854
for (i = 1; i < jl_core_module->bindings.size; i += 2) {
855855
if (table[i] != HT_NOTFOUND) {
856856
jl_binding_t *b = (jl_binding_t*)table[i];
857-
jl_value_t *v = b->value;
857+
jl_value_t *v = jl_atomic_load_relaxed(&b->value);
858858
if (v) {
859859
if (jl_is_unionall(v))
860860
v = jl_unwrap_unionall(v);

src/jl_uv.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ JL_DLLEXPORT int jl_process_events(void)
208208
jl_task_t *ct = jl_current_task;
209209
uv_loop_t *loop = jl_io_loop;
210210
jl_gc_safepoint_(ct->ptls);
211-
if (loop && (_threadedregion || ct->tid == 0)) {
211+
if (loop && (_threadedregion || jl_atomic_load_relaxed(&ct->tid) == 0)) {
212212
if (jl_atomic_load(&jl_uv_n_waiters) == 0 && jl_mutex_trylock(&jl_uv_mutex)) {
213213
loop->stop_flag = 0;
214214
int r = uv_run(loop, UV_RUN_NOWAIT);
@@ -414,7 +414,7 @@ JL_DLLEXPORT int jl_fs_write(uv_os_fd_t handle, const char *data, size_t len,
414414
{
415415
jl_task_t *ct = jl_get_current_task();
416416
// TODO: fix this cheating
417-
if (jl_get_safe_restore() || ct == NULL || ct->tid != 0)
417+
if (jl_get_safe_restore() || ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0)
418418
#ifdef _OS_WINDOWS_
419419
return WriteFile(handle, data, len, NULL, NULL);
420420
#else
@@ -514,7 +514,7 @@ JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n)
514514

515515
// TODO: Hack to make CoreIO thread-safer
516516
jl_task_t *ct = jl_get_current_task();
517-
if (ct == NULL || ct->tid != 0) {
517+
if (ct == NULL || jl_atomic_load_relaxed(&ct->tid) != 0) {
518518
if (stream == JL_STDOUT) {
519519
fd = UV_STDOUT_FD;
520520
}

0 commit comments

Comments
 (0)