Commit 2c9992a5 by Thomas Lively

Subzero: Fixed deadlock when _start is first function

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 .
parent adf352bc
...@@ -74,6 +74,7 @@ bool ASanInstrumentation::isInstrumentable(Cfg *Func) { ...@@ -74,6 +74,7 @@ bool ASanInstrumentation::isInstrumentable(Cfg *Func) {
// types of the redzones and their associated globals match so that they are // types of the redzones and their associated globals match so that they are
// laid out together in memory. // laid out together in memory.
void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) {
std::unique_lock<std::mutex> _(GlobalsMutex);
if (DidProcessGlobals) if (DidProcessGlobals)
return; return;
VariableDeclarationList NewGlobals; VariableDeclarationList NewGlobals;
...@@ -135,7 +136,6 @@ void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { ...@@ -135,7 +136,6 @@ void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) {
Globals.clear(); Globals.clear();
Globals.merge(&NewGlobals); Globals.merge(&NewGlobals);
DidProcessGlobals = true; DidProcessGlobals = true;
GlobalsDoneCV.notify_all();
// Log the new set of globals // Log the new set of globals
if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) { if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) {
...@@ -332,13 +332,8 @@ void ASanInstrumentation::instrumentStart(Cfg *Func) { ...@@ -332,13 +332,8 @@ void ASanInstrumentation::instrumentStart(Cfg *Func) {
auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall); auto *Call = InstCall::create(Func, NumArgs, Void, ShadowMemInit, NoTailCall);
Func->getEntryNode()->getInsts().push_front(Call); Func->getEntryNode()->getInsts().push_front(Call);
// wait to get the final count of global redzones instrumentGlobals(*getGlobals());
if (!DidProcessGlobals) {
GlobalsLock.lock();
while (!DidProcessGlobals)
GlobalsDoneCV.wait(GlobalsLock);
GlobalsLock.release();
}
Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum)); Call->addArg(ConstantInteger32::create(Ctx, IceType_i32, RzGlobalsNum));
Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName))); Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzArrayName)));
Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName))); Call->addArg(Ctx->getConstantSym(0, Ctx->getGlobalString(RzSizesName)));
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include "IceGlobalInits.h" #include "IceGlobalInits.h"
#include "IceInstrumentation.h" #include "IceInstrumentation.h"
#include <condition_variable>
namespace Ice { namespace Ice {
class ASanInstrumentation : public Instrumentation { class ASanInstrumentation : public Instrumentation {
...@@ -33,9 +31,7 @@ class ASanInstrumentation : public Instrumentation { ...@@ -33,9 +31,7 @@ class ASanInstrumentation : public Instrumentation {
ASanInstrumentation &operator=(const ASanInstrumentation &) = delete; ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;
public: public:
ASanInstrumentation(GlobalContext *Ctx) ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {
: Instrumentation(Ctx), RzNum(0),
GlobalsLock(GlobalsMutex, std::defer_lock) {
ICE_TLS_INIT_FIELD(LocalDtors); ICE_TLS_INIT_FIELD(LocalDtors);
} }
void instrumentGlobals(VariableDeclarationList &Globals) override; void instrumentGlobals(VariableDeclarationList &Globals) override;
...@@ -57,8 +53,6 @@ private: ...@@ -57,8 +53,6 @@ private:
bool DidProcessGlobals = false; bool DidProcessGlobals = false;
SizeT RzGlobalsNum = 0; SizeT RzGlobalsNum = 0;
std::mutex GlobalsMutex; std::mutex GlobalsMutex;
std::unique_lock<std::mutex> GlobalsLock;
std::condition_variable GlobalsDoneCV;
}; };
} // end of namespace Ice } // end of namespace Ice
......
...@@ -482,6 +482,10 @@ public: ...@@ -482,6 +482,10 @@ public:
return LockedPtr<StringPool>(Strings.get(), &StringsLock); 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 /// Number of function blocks that can be queued before waiting for
/// translation /// translation
/// threads to consume. /// threads to consume.
...@@ -612,6 +616,8 @@ private: ...@@ -612,6 +616,8 @@ private:
LockedPtr<VariableDeclarationList> _(&Globals, &InitAllocLock); LockedPtr<VariableDeclarationList> _(&Globals, &InitAllocLock);
if (Globls != nullptr) { if (Globls != nullptr) {
Globals.merge(Globls.get()); Globals.merge(Globls.get());
if (!BuildDefs::minimal() && Instrumentor != nullptr)
Instrumentor->setHasSeenGlobals();
} }
} }
......
...@@ -118,4 +118,18 @@ void Instrumentation::instrumentInst(LoweringContext &Context) { ...@@ -118,4 +118,18 @@ void Instrumentation::instrumentInst(LoweringContext &Context) {
} }
} }
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 } // end of namespace Ice
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "IceDefs.h" #include "IceDefs.h"
#include <condition_variable>
namespace Ice { namespace Ice {
class LoweringContext; class LoweringContext;
...@@ -41,11 +43,14 @@ class Instrumentation { ...@@ -41,11 +43,14 @@ class Instrumentation {
public: public:
Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {} Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {}
virtual ~Instrumentation() = default;
virtual void instrumentGlobals(VariableDeclarationList &) {} virtual void instrumentGlobals(VariableDeclarationList &) {}
void instrumentFunc(Cfg *Func); void instrumentFunc(Cfg *Func);
void setHasSeenGlobals();
protected: protected:
virtual void instrumentInst(LoweringContext &Context); virtual void instrumentInst(LoweringContext &Context);
LockedPtr<VariableDeclarationList> getGlobals();
private: private:
virtual bool isInstrumentable(Cfg *) { return true; } virtual bool isInstrumentable(Cfg *) { return true; }
...@@ -78,6 +83,11 @@ private: ...@@ -78,6 +83,11 @@ private:
protected: protected:
GlobalContext *Ctx; GlobalContext *Ctx;
private:
bool HasSeenGlobals = false;
std::mutex GlobalsSeenMutex;
std::condition_variable GlobalsSeenCV;
}; };
} // end of namespace Ice } // end of namespace Ice
......
; 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment