It was previously the case that instrumentStart in ASanInstrumentation would block until instrumentGlobals had completed. This was because instrumentStart depends on the global redzones having been inserted. However, instrumentGlobals was not called until the first function was popped off the emit queue, and when _start was the first function, it was not placed on the emit queue until after it had been instrumented and lowered. instrumentStart was waiting for instrumentGlobals, which could not happen until instrumentStart completed.
BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com, stichnot@chromium.org
Review URL: https://codereview.chromium.org/
2165493002 .
// types of the redzones and their associated globals match so that they are
// laid out together in memory.
void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) {
+ std::unique_lock<std::mutex> _(GlobalsMutex);
if (DidProcessGlobals)
return;
VariableDeclarationList NewGlobals;
Globals.clear();
Globals.merge(&NewGlobals);
DidProcessGlobals = true;
- GlobalsDoneCV.notify_all();
// Log the new set of globals
if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) {
auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall);
Func->getEntryNode()->getInsts().push_front(Call);
- // wait to get the final count of global redzones
- if (!DidProcessGlobals) {
- GlobalsLock.lock();
- while (!DidProcessGlobals)
- GlobalsDoneCV.wait(GlobalsLock);
- GlobalsLock.release();
- }
+ instrumentGlobals(*getGlobals());
+
Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum));
Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName)));
Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName)));
#include "IceGlobalInits.h"
#include "IceInstrumentation.h"
-#include <condition_variable>
-
namespace Ice {
class ASanInstrumentation : public Instrumentation {
ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;
public:
- ASanInstrumentation(GlobalContext *Ctx)
- : Instrumentation(Ctx), RzNum(0),
- GlobalsLock(GlobalsMutex, std::defer_lock) {
+ ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {
ICE_TLS_INIT_FIELD(LocalDtors);
}
void instrumentGlobals(VariableDeclarationList &Globals) override;
bool DidProcessGlobals = false;
SizeT RzGlobalsNum = 0;
std::mutex GlobalsMutex;
- std::unique_lock<std::mutex> GlobalsLock;
- std::condition_variable GlobalsDoneCV;
};
} // end of namespace Ice
return LockedPtr<StringPool>(Strings.get(), &StringsLock);
}
+ LockedPtr<VariableDeclarationList> getGlobals() {
+ return LockedPtr<VariableDeclarationList>(&Globals, &InitAllocLock);
+ }
+
/// Number of function blocks that can be queued before waiting for
/// translation
/// threads to consume.
LockedPtr<VariableDeclarationList> _(&Globals, &InitAllocLock);
if (Globls != nullptr) {
Globals.merge(Globls.get());
+ if (!BuildDefs::minimal() && Instrumentor != nullptr)
+ Instrumentor->setHasSeenGlobals();
}
}
}
}
+void Instrumentation::setHasSeenGlobals() {
+ {
+ std::unique_lock<std::mutex> _(GlobalsSeenMutex);
+ HasSeenGlobals = true;
+ }
+ GlobalsSeenCV.notify_all();
+}
+
+LockedPtr<VariableDeclarationList> Instrumentation::getGlobals() {
+ std::unique_lock<std::mutex> GlobalsLock(GlobalsSeenMutex);
+ GlobalsSeenCV.wait(GlobalsLock, [this] { return HasSeenGlobals; });
+ return Ctx->getGlobals();
+}
+
} // end of namespace Ice
#include "IceDefs.h"
+#include <condition_variable>
+
namespace Ice {
class LoweringContext;
public:
Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {}
+ virtual ~Instrumentation() = default;
virtual void instrumentGlobals(VariableDeclarationList &) {}
void instrumentFunc(Cfg *Func);
+ void setHasSeenGlobals();
protected:
virtual void instrumentInst(LoweringContext &Context);
+ LockedPtr<VariableDeclarationList> getGlobals();
private:
virtual bool isInstrumentable(Cfg *) { return true; }
protected:
GlobalContext *Ctx;
+
+private:
+ bool HasSeenGlobals = false;
+ std::mutex GlobalsSeenMutex;
+ std::condition_variable GlobalsSeenCV;
};
} // end of namespace Ice
--- /dev/null
+; Check that Subzero can instrument _start when there are no globals.
+; Previously Subzero would deadlock when _start was the first function. Also
+; test that instrumenting start does not deadlock waiting for nonexistent
+; global initializers to be lowered.
+
+; REQUIRES: no_minimal_build
+
+; RUN: %p2i -i %s --args -verbose=inst -fsanitize-address \
+; RUN: | FileCheck --check-prefix=DUMP %s
+
+; RUN: %p2i -i %s --args -verbose=inst -fsanitize-address -threads=0 \
+; RUN: | FileCheck --check-prefix=DUMP %s
+
+
+define void @_start(i32 %arg) {
+ ret void
+}
+
+; DUMP: __asan_init