Commit 187b3dfa by Karl Schimpf

Fix locking for printing error messages.

The method TopLevelParser::ErrorAt applies a lock to print the error message. Unfortunately, it keeps the lock longer than necessary, resulting in deadlock (on following fatal message) if error recovery is not allowed. Fixed by limiting scope of lock to only apply to the printing of the error message. Modified ClFlags to allow a "reset", and made ClFlags modifiable by bitcode munge tests. This allowed us to test this problem as a unit test. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4138 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/1091023002
parent d8fb3d33
...@@ -245,6 +245,43 @@ void ClFlags::parseFlags(int argc, char **argv) { ...@@ -245,6 +245,43 @@ void ClFlags::parseFlags(int argc, char **argv) {
AppName = IceString(argv[0]); AppName = IceString(argv[0]);
} }
void ClFlags::resetClFlags(ClFlags &OutFlags) {
// bool fields
OutFlags.AllowErrorRecovery = false;
OutFlags.AllowUninitializedGlobals = false;
OutFlags.DataSections = false;
OutFlags.DecorateAsm = false;
OutFlags.DisableInternal = false;
OutFlags.DisableIRGeneration = false;
OutFlags.DisableTranslation = false;
OutFlags.DumpStats = false;
OutFlags.FunctionSections = false;
OutFlags.GenerateUnitTestMessages = false;
OutFlags.PhiEdgeSplit = false;
OutFlags.RandomNopInsertion = false;
OutFlags.RandomRegAlloc = false;
OutFlags.SubzeroTimingEnabled = false;
OutFlags.TimeEachFunction = false;
OutFlags.UseSandboxing = false;
// Enum and integer fields.
OutFlags.Opt = Opt_m1;
OutFlags.OutFileType = FT_Iasm;
OutFlags.RandomMaxNopsPerInstruction = 0;
OutFlags.RandomNopProbabilityAsPercentage = 0;
OutFlags.TArch = TargetArch_NUM;
OutFlags.VMask = IceV_None;
// IceString fields.
OutFlags.DefaultFunctionPrefix = "";
OutFlags.DefaultGlobalPrefix = "";
OutFlags.TestPrefix = "";
OutFlags.TimingFocusOn = "";
OutFlags.TranslateOnly = "";
OutFlags.VerboseFocusOn = "";
// size_t and 64-bit fields.
OutFlags.NumTranslationThreads = 0;
OutFlags.RandomSeed = 0;
}
void ClFlags::getParsedClFlags(ClFlags &OutFlags) { void ClFlags::getParsedClFlags(ClFlags &OutFlags) {
if (::DisableIRGeneration) if (::DisableIRGeneration)
::DisableTranslation = true; ::DisableTranslation = true;
......
...@@ -26,27 +26,10 @@ class ClFlags { ...@@ -26,27 +26,10 @@ class ClFlags {
ClFlags &operator=(const ClFlags &) = delete; ClFlags &operator=(const ClFlags &) = delete;
public: public:
ClFlags() ClFlags() { resetClFlags(*this); }
: // bool fields.
AllowErrorRecovery(false),
AllowUninitializedGlobals(false), DataSections(false),
DecorateAsm(false), DisableInternal(false), DisableIRGeneration(false),
DisableTranslation(false), DumpStats(false), FunctionSections(false),
GenerateUnitTestMessages(false), PhiEdgeSplit(false),
RandomNopInsertion(false), RandomRegAlloc(false),
SubzeroTimingEnabled(false), TimeEachFunction(false),
UseSandboxing(false),
// Enum and integer fields.
Opt(Opt_m1), OutFileType(FT_Iasm), RandomMaxNopsPerInstruction(0),
RandomNopProbabilityAsPercentage(0), TArch(TargetArch_NUM),
VMask(IceV_None),
// IceString fields.
DefaultFunctionPrefix(""), DefaultGlobalPrefix(""), TestPrefix(""),
TimingFocusOn(""), TranslateOnly(""), VerboseFocusOn(""),
// size_t and 64-bit fields.
NumTranslationThreads(0), RandomSeed(0) {}
static void parseFlags(int argc, char *argv[]); static void parseFlags(int argc, char *argv[]);
static void resetClFlags(ClFlags &OutFlags);
static void getParsedClFlags(ClFlags &OutFlags); static void getParsedClFlags(ClFlags &OutFlags);
static void getParsedClFlagsExtra(ClFlagsExtra &OutFlagsExtra); static void getParsedClFlagsExtra(ClFlagsExtra &OutFlagsExtra);
......
...@@ -486,10 +486,12 @@ bool TopLevelParser::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit, ...@@ -486,10 +486,12 @@ bool TopLevelParser::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit,
ErrorStatus.assign(Ice::EC_Bitcode); ErrorStatus.assign(Ice::EC_Bitcode);
++NumErrors; ++NumErrors;
Ice::GlobalContext *Context = Translator.getContext(); Ice::GlobalContext *Context = Translator.getContext();
{ // Lock while printing out error message.
Ice::OstreamLocker L(Context); Ice::OstreamLocker L(Context);
raw_ostream &OldErrStream = setErrStream(Context->getStrDump()); raw_ostream &OldErrStream = setErrStream(Context->getStrDump());
NaClBitcodeParser::ErrorAt(Level, Bit, Message); NaClBitcodeParser::ErrorAt(Level, Bit, Message);
setErrStream(OldErrStream); setErrStream(OldErrStream);
}
if (Level >= naclbitc::Error && if (Level >= naclbitc::Error &&
!Translator.getFlags().getAllowErrorRecovery()) !Translator.getFlags().getAllowErrorRecovery())
Fatal(); Fatal();
......
...@@ -19,19 +19,25 @@ ...@@ -19,19 +19,25 @@
namespace IceTest { namespace IceTest {
bool IceTest::SubzeroBitcodeMunger::runTest(const char *TestName, void IceTest::SubzeroBitcodeMunger::resetFlags() {
const uint64_t Munges[], Ice::ClFlags::resetClFlags(Flags);
size_t MungeSize) { resetMungeFlags();
const bool AddHeader = true; }
setupTest(TestName, Munges, MungeSize, AddHeader);
Ice::ClFlags Flags; void IceTest::SubzeroBitcodeMunger::resetMungeFlags() {
Flags.setAllowErrorRecovery(true); Flags.setAllowErrorRecovery(true);
Flags.setGenerateUnitTestMessages(true); Flags.setGenerateUnitTestMessages(true);
Flags.setOptLevel(Ice::Opt_m1); Flags.setOptLevel(Ice::Opt_m1);
Flags.setOutFileType(Ice::FT_Iasm); Flags.setOutFileType(Ice::FT_Iasm);
Flags.setTargetArch(Ice::Target_X8632); Flags.setTargetArch(Ice::Target_X8632);
Flags.setVerbose(Ice::IceV_Instructions); Flags.setVerbose(Ice::IceV_Instructions);
}
bool IceTest::SubzeroBitcodeMunger::runTest(const char *TestName,
const uint64_t Munges[],
size_t MungeSize) {
const bool AddHeader = true;
setupTest(TestName, Munges, MungeSize, AddHeader);
Ice::GlobalContext Ctx(DumpStream, DumpStream, nullptr, Flags); Ice::GlobalContext Ctx(DumpStream, DumpStream, nullptr, Flags);
Ice::PNaClTranslator Translator(&Ctx); Ice::PNaClTranslator Translator(&Ctx);
Translator.translateBuffer(TestName, MungedInput.get()); Translator.translateBuffer(TestName, MungedInput.get());
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h" #include "llvm/Bitcode/NaCl/NaClBitcodeMunge.h"
#include "IceClFlags.h"
namespace IceTest { namespace IceTest {
// Class to run tests on Subzero's bitcode parser. Runs a Subzero // Class to run tests on Subzero's bitcode parser. Runs a Subzero
...@@ -27,7 +29,9 @@ class SubzeroBitcodeMunger : public llvm::NaClBitcodeMunger { ...@@ -27,7 +29,9 @@ class SubzeroBitcodeMunger : public llvm::NaClBitcodeMunger {
public: public:
SubzeroBitcodeMunger(const uint64_t Records[], size_t RecordSize, SubzeroBitcodeMunger(const uint64_t Records[], size_t RecordSize,
uint64_t RecordTerminator) uint64_t RecordTerminator)
: llvm::NaClBitcodeMunger(Records, RecordSize, RecordTerminator) {} : llvm::NaClBitcodeMunger(Records, RecordSize, RecordTerminator) {
resetMungeFlags();
}
/// Runs PNaClTranslator to translate bitcode records (with defined /// Runs PNaClTranslator to translate bitcode records (with defined
/// record Munges), and puts output into DumpResults. Returns true /// record Munges), and puts output into DumpResults. Returns true
...@@ -39,6 +43,15 @@ public: ...@@ -39,6 +43,15 @@ public:
uint64_t NoMunges[] = {0}; uint64_t NoMunges[] = {0};
return runTest(TestName, NoMunges, 0); return runTest(TestName, NoMunges, 0);
} }
/// Sets flags back to default assumptions for munging.
void resetFlags();
/// Flags to use to run tests. Use to change default assumptions.
Ice::ClFlags Flags;
private:
void resetMungeFlags();
}; };
} // end of namespace IceTest } // end of namespace IceTest
......
...@@ -63,6 +63,12 @@ TEST(IceParseInstsTest, NonexistentCallArg) { ...@@ -63,6 +63,12 @@ TEST(IceParseInstsTest, NonexistentCallArg) {
EXPECT_FALSE(Munger.runTest("Nonexistent call arg")); EXPECT_FALSE(Munger.runTest("Nonexistent call arg"));
EXPECT_EQ("Error(66:4): Invalid function record: <34 0 4 2 100>\n", EXPECT_EQ("Error(66:4): Invalid function record: <34 0 4 2 100>\n",
Munger.getTestResults()); Munger.getTestResults());
// Show that we generate a fatal error when not allowing error recovery.
Munger.Flags.setAllowErrorRecovery(false);
EXPECT_DEATH(
Munger.runTest("Nonexistent call arg"),
".*ERROR: Unable to continue.*");
} }
/// Test how we recognize alignments in alloca instructions. /// Test how we recognize alignments in alloca instructions.
......
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