def runTest(self): err1 = windowsPathAssertFwdSlashes.splitlines() # err2 = windowsPathAssertBwSlashes.splitlines() assertionMsg1 = AssertionHelper.getAssertion(err1) # assertionMsg2 = AssertionHelper.getAssertion(err2) sanitizedMsg1 = AssertionHelper.getSanitizedAssertionPattern( assertionMsg1) # sanitizedMsg2 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg2) expectedMsg = ( "Assertion failure: block\\->graph\\(\\)\\.osrBlock\\(\\), at " "([a-zA-Z]:)?/.+/Lowering\\.cpp(:[0-9]+)+") self.assertEqual(sanitizedMsg1, expectedMsg) # We currently don't support backward slashes, but if we add support, uncomment this test # self.assertEqual(sanitizedMsg2, expectedMsg) self.assertTrue(re.match(expectedMsg, assertionMsg1)) # We currently don't support backward slashes, but if we add support, uncomment this test # self.assertTrue(re.match(expectedMsg, assertionMsg2)) # Ensure the sanitized message can be compiled as regex without errors re.compile(sanitizedMsg1)
def runTest(self): err1 = windowsPathAssertFwdSlashes.splitlines() err2 = windowsPathAssertBwSlashes.splitlines() assertionMsg1 = AssertionHelper.getAssertion(err1) assertionMsg2 = AssertionHelper.getAssertion(err2) sanitizedMsg1 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg1) sanitizedMsg2 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg2) expectedMsg = (r"Assertion failure: block->graph\(\)\.osrBlock\(\), at " r"([a-zA-Z]:)?/.+/Lowering\.cpp(:[0-9]+)+") assert sanitizedMsg1 == expectedMsg assert sanitizedMsg2 == expectedMsg _check_regex_matches(err1, sanitizedMsg1)
def runTest(self): err = asanFFAbort.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err, False)) expectedMsg = "==[0-9]{2,}==ERROR: AddressSanitizer: SEGV on unknown address 0x[0-9a-fA-F]+ \\(pc 0x[0-9a-fA-F]+ sp 0x[0-9a-fA-F]+ bp 0x[0-9a-fA-F]+ T0\\)" self.assertEqual(sanitizedMsg, expectedMsg)
def test_AssertionHelperTestWindowsPathSanitizing(): err1 = windowsPathAssertFwdSlashes.splitlines() err2 = windowsPathAssertBwSlashes.splitlines() assertionMsg1 = AssertionHelper.getAssertion(err1) assertionMsg2 = AssertionHelper.getAssertion(err2) sanitizedMsg1 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg1) sanitizedMsg2 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg2) expectedMsg = (r"Assertion failure: block->graph\(\)\.osrBlock\(\), at " r"([a-zA-Z]:)?/.+/Lowering\.cpp(:[0-9]+)+") assert sanitizedMsg1 == expectedMsg assert sanitizedMsg2 == expectedMsg _check_regex_matches(err1, sanitizedMsg1)
def runTest(self): err = jsSelfHostedAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = 'Self\\-hosted JavaScript assertion info: "([a-zA-Z]:)?/.+/Intl\\.js:[0-9]+: non\\-canonical BestAvailableLocale locale"' self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = jsshellMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err, False)) expectedMsg = "Hit MOZ_CRASH\\(named lambda static scopes should have been skipped\\) at /.+/ScopeObject\\.cpp:[0-9]+" self.assertEqual(sanitizedMsg, expectedMsg)
def test_AssertionHelperTestASanNegativeSize(): err = asanNegativeSize.splitlines() assert AssertionHelper.getAssertion(err) is None assertMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedAssertMsg = r"ERROR: AddressSanitizer: negative-size-param: \(size=-[0-9]{2,}\)" assert assertMsg == expectedAssertMsg
def runTest(self): err = asanNegativeSize.splitlines() self.assertEqual(AssertionHelper.getAssertion(err), None) assertMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedAssertMsg = r"ERROR: AddressSanitizer: negative\-size\-param: \(size=\-[0-9]{2,}\)" self.assertEqual(assertMsg, expectedAssertMsg)
def runTest(self): err = jsshellMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = "Hit MOZ_CRASH\\(named lambda static scopes should have been skipped\\) at ([a-zA-Z]:)?/.+/ScopeObject\\.cpp:[0-9]+" self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = asanFFAbort.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err, False)) expectedMsg = "###!!! ASSERTION: Unexpected non\-ASCII character: '!\(\*s2 & ~0x[0-9a-fA-F]+\)', file \.\./\.\./\.\./dist/include/nsCharTraits\.h, line [0-9]+" self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = cppUnhandledException.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = "terminate called after throwing an instance of 'std::regex_error'" self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = chakraAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = 'ASSERTION [0-9]{2,}: \\\\(([a-zA-Z]:)?/.+/ByteCodeEmitter\\.cpp, line [0-9]+\\) scope\\->HasInnerScopeIndex\\(\\)' self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = asanNegativeSize.splitlines() assert AssertionHelper.getAssertion(err) is None assertMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedAssertMsg = r"ERROR: AddressSanitizer: negative-size-param: \(size=-[0-9]{2,}\)" assert assertMsg == expectedAssertMsg
def runTest(self): err = jsshellMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(named lambda static scopes should have been skipped\) at " r"([a-zA-Z]:)?/.+/ScopeObject\.cpp(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_02(self): err = rustPanic2.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = ( r"thread 'RenderBackend' panicked at 'called `Option::unwrap\(\)` on a `None` value', " r"([a-zA-Z]:)?/.+/option\.rs(:[0-9]+)+") self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = asanFFAbort.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err, False)) expectedMsg = "==[0-9]{2,}==ERROR: AddressSanitizer: SEGV on unknown address 0x[0-9a-fA-F]+ \\(pc 0x[0-9a-fA-F]+ sp 0x[0-9a-fA-F]+ bp 0x[0-9a-fA-F]+ T0\\)" self.assertEqual(sanitizedMsg, expectedMsg)
def test_AssertionHelperTestMozCrashWithPath(): err = mozCrashWithPath.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(([a-zA-Z]:)?/.+/celt_decoder\.c(:[0-9]+)+ assertion failed: " r"st->start < st->end\) at nil(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = multiMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(good message\) at " r"([a-zA-Z]:)?/.+/spatial_node\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = asanFFAbort.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err, False)) expectedMsg = "###!!! ASSERTION: Unexpected non\-ASCII character: '!\(\*s2 & ~0x[0-9a-fA-F]+\)', file \.\./\.\./\.\./dist/include/nsCharTraits\.h, line [0-9]+" self.assertEqual(sanitizedMsg, expectedMsg)
def test_02(self): err = rustPanic2.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"thread 'RenderBackend' panicked at 'called `Option::unwrap\(\)` on a `None` value', " r"([a-zA-Z]:)?/.+/option\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = mozCrashWithPath.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(([a-zA-Z]:)?/.+/celt_decoder\.c(:[0-9]+)+ assertion failed: " r"st->start < st->end\) at nil(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = cppUnhandledException.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = "terminate called after throwing an instance of 'std::regex_error'" assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_03(self): err = rustPanic3.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) assert len(sanitizedMsg) == 3 assert sanitizedMsg[0] == r"thread '<unnamed>' panicked at 'assertion failed: `\(left == right\)`" assert sanitizedMsg[-1] == r" right: `Block`', ([a-zA-Z]:)?/.+/style_adjuster\.rs(:[0-9]+)+" _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestMultiMozCrash(): err = multiMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(good message\) at " r"([a-zA-Z]:)?/.+/spatial_node\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_01(self): err = rustPanic1.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"thread 'StyleThread#[0-9]+' panicked at 'assertion failed: self\.get_data\(\)\.is_some\(\)', " r"([a-zA-Z]:)?/.+/wrapper\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_01(self): err = rustPanic1.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = ( r"thread 'StyleThread#[0-9]+' panicked at 'assertion failed: self\.get_data\(\)\.is_some\(\)', " r"([a-zA-Z]:)?/.+/wrapper\.rs(:[0-9]+)+") self.assertEqual(sanitizedMsg, expectedMsg)
def test_AssertionHelperTestMozCrash(): err = jsshellMozCrash.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"Hit MOZ_CRASH\(named lambda static scopes should have been skipped\) at " r"([a-zA-Z]:)?/.+/ScopeObject\.cpp(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestRustPanic03(): err = rustPanic3.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) assert len(sanitizedMsg) == 3 assert sanitizedMsg[0] == r"thread '<unnamed>' panicked at 'assertion failed: `\(left == right\)`" assert sanitizedMsg[-1] == r" right: `Block`', ([a-zA-Z]:)?/.+/style_adjuster\.rs(:[0-9]+)+" _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestRustPanic02(): err = rustPanic2.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"thread 'RenderBackend' panicked at 'called `Option::unwrap\(\)` on a `None` value', " r"([a-zA-Z]:)?/.+/option\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestRustPanic01(): err = rustPanic1.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r"thread 'StyleThread#[0-9]+' panicked at 'assertion failed: self\.get_data\(\)\.is_some\(\)', " r"([a-zA-Z]:)?/.+/wrapper\.rs(:[0-9]+)+") assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestCPPUnhandledException(): err = cppUnhandledException.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = "terminate called after throwing an instance of 'std::regex_error'" assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err1 = windowsPathAssertFwdSlashes.splitlines() err2 = windowsPathAssertBwSlashes.splitlines() assertionMsg1 = AssertionHelper.getAssertion(err1) assertionMsg2 = AssertionHelper.getAssertion(err2) sanitizedMsg1 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg1) sanitizedMsg2 = AssertionHelper.getSanitizedAssertionPattern(assertionMsg2) expectedMsg = "Assertion failure: block\\->graph\\(\\)\\.osrBlock\\(\\), at ([a-zA-Z]:)?/.+/Lowering\\.cpp:[0-9]+" self.assertEqual(sanitizedMsg1, expectedMsg) # We currently don't support backward slashes, but if we add support, uncomment this test # self.assertEqual(sanitizedMsg2, expectedMsg) self.assertTrue(re.match(expectedMsg, assertionMsg1))
def test_AssertionHelperTestChakraAssert(): err = chakraAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r'ASSERTION [0-9]{2,}: \(([a-zA-Z]:)?/.+/ByteCodeEmitter\.cpp, line [0-9]+\) ' r'scope->HasInnerScopeIndex\(\)') assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_AssertionHelperTestJSSelfHosted(): err = jsSelfHostedAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r'Self-hosted JavaScript assertion info: "([a-zA-Z]:)?/.+/Intl\.js(:[0-9]+)+: ' r'non-canonical BestAvailableLocale locale"') assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = jsSelfHostedAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r'Self-hosted JavaScript assertion info: "([a-zA-Z]:)?/.+/Intl\.js(:[0-9]+)+: ' r'non-canonical BestAvailableLocale locale"') assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = chakraAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) expectedMsg = (r'ASSERTION [0-9]{2,}: \(([a-zA-Z]:)?/.+/ByteCodeEmitter\.cpp, line [0-9]+\) ' r'scope->HasInnerScopeIndex\(\)') assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = asanOverflow.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedMsg = [ "ERROR: AddressSanitizer: heap\\-buffer\\-overflow", "READ of size 8 at 0x[0-9a-fA-F]+ thread T[0-9]{2,} \\(MediaPlayback #1\\)" ] self.assertEqual(sanitizedMsg, expectedMsg)
def runTest(self): err = asanOverflow.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedMsg = [ r"ERROR: AddressSanitizer: heap-buffer-overflow", r"READ of size 8 at 0x[0-9a-fA-F]+ thread T[0-9]{2,} \(MediaPlayback #1\)" ] assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = cppUnhandledException.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = "terminate called after throwing an instance of 'std::regex_error'" self.assertEqual(sanitizedMsg, expectedMsg) # Ensure the sanitized message can be compiled as regex without errors re.compile(sanitizedMsg)
def test_AssertionHelperTestAuxiliaryAbortASan(): err = asanOverflow.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAuxiliaryAbortMessage(err)) expectedMsg = [ r"ERROR: AddressSanitizer: heap-buffer-overflow", r"READ of size 8 at 0x[0-9a-fA-F]+ thread T[0-9]{2,} \(MediaPlayback #1\)" ] assert sanitizedMsg == expectedMsg _check_regex_matches(err, sanitizedMsg)
def test_03(self): err = rustPanic3.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) self.assertEqual(len(sanitizedMsg), 3) self.assertEqual( sanitizedMsg[0], r"thread '<unnamed>' panicked at 'assertion failed: `\(left == right\)`" ) self.assertEqual( sanitizedMsg[-1], r" right: `Block`', ([a-zA-Z]:)?/.+/style_adjuster\.rs(:[0-9]+)+")
def test_AssertionHelperTestMozCrashMultiLine(): err = mozCrashMultiLine.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) assert sanitizedMsg[0] == ( r"Hit MOZ_CRASH\(assertion failed:" r" combined_local_clip_rect\.size\.width >= 0\.0 &&") assert sanitizedMsg[-1] == ( r" combined_local_clip_rect\.size\.height >= 0\.0\)" r" at gfx/wr/webrender/src/prim_store/mod\.rs(:[0-9]+)+") _check_regex_matches(err, sanitizedMsg)
def runTest(self): err = chakraAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = ( 'ASSERTION [0-9]{2,}: \\(([a-zA-Z]:)?/.+/ByteCodeEmitter\\.cpp, line [0-9]+\\) ' 'scope\\->HasInnerScopeIndex\\(\\)') self.assertEqual(sanitizedMsg, expectedMsg) # Ensure the sanitized message can be compiled as regex without errors re.compile(sanitizedMsg)
def runTest(self): err = jsSelfHostedAssert.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = ( 'Self\\-hosted JavaScript assertion info: "([a-zA-Z]:)?/.+/Intl\\.js(:[0-9]+)+: ' 'non\\-canonical BestAvailableLocale locale"') self.assertEqual(sanitizedMsg, expectedMsg) # Ensure the sanitized message can be compiled as regex without errors re.compile(sanitizedMsg)
def runTest(self): err = mozCrashWithPath.splitlines() sanitizedMsg = AssertionHelper.getSanitizedAssertionPattern( AssertionHelper.getAssertion(err)) expectedMsg = ( "Hit MOZ_CRASH\\(([a-zA-Z]:)?/.+/celt_decoder\\.c(:[0-9]+)+ assertion failed: " "st\\->start < st\\->end\\) at nil(:[0-9]+)+") self.assertEqual(sanitizedMsg, expectedMsg) # Ensure the sanitized message can be compiled as regex without errors re.compile(sanitizedMsg)
def runTest(self): err = v8Abort.splitlines() sanitizedMsgs = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) self.assertTrue(isinstance(sanitizedMsgs, list)) self.assertEqual(len(sanitizedMsgs), 2) expectedMsgs = [ "# Fatal error in \\.\\./src/compiler\\.cc, line [0-9]+", "# Check failed: !feedback_vector_\\->metadata\\(\\)\\->SpecDiffersFrom\\( literal\\(\\)\\->feedback_vector_spec\\(\\)\\)\\." ] self.assertEqual(sanitizedMsgs[0], expectedMsgs[0]) self.assertEqual(sanitizedMsgs[1], expectedMsgs[1])
def runTest(self): err = v8Abort.splitlines() sanitizedMsgs = AssertionHelper.getSanitizedAssertionPattern(AssertionHelper.getAssertion(err)) assert isinstance(sanitizedMsgs, list) assert len(sanitizedMsgs) == 2 expectedMsgs = [ r"# Fatal error in \.\./src/compiler\.cc, line [0-9]+", (r"# Check failed: !feedback_vector_->metadata\(\)->SpecDiffersFrom\( " r"literal\(\)->feedback_vector_spec\(\)\)\.") ] assert sanitizedMsgs == expectedMsgs _check_regex_matches(err, sanitizedMsgs)
def createCrashSignature(self, forceCrashAddress=False, forceCrashInstruction=False, maxFrames=8, minimumSupportedVersion=13): ''' @param forceCrashAddress: If True, the crash address will be included in any case @type forceCrashAddress: bool @param forceCrashInstruction: If True, the crash instruction will be included in any case @type forceCrashInstruction: bool @param maxFrames: How many frames (at most) should be included in the signature @type maxFrames: int @param minimumSupportedVersion: The minimum crash signature standard version that the generated signature should be valid for (10 => 1.0, 13 => 1.3) @type minimumSupportedVersion: int @rtype: CrashSignature @return: A crash signature object ''' # Determine the actual number of frames based on how many we got if len(self.backtrace) > maxFrames: numFrames = maxFrames else: numFrames = len(self.backtrace) symptomArr = [] # Memorize where we find our abort messages abortMsgInCrashdata = False # See if we have an abort message and if so, get a sanitized version of it abortMsgs = AssertionHelper.getAssertion(self.rawStderr) if abortMsgs is None and minimumSupportedVersion >= 13: # Look for abort messages also inside crashdata # only on version 1.3 or higher, because the "crashdata" source # type for output matching was added in that version. abortMsgs = AssertionHelper.getAssertion(self.rawCrashData) if abortMsgs != None: abortMsgInCrashdata = True # Still no abort message, fall back to auxiliary abort messages (ASan/UBSan) if abortMsgs is None: abortMsgs = AssertionHelper.getAuxiliaryAbortMessage(self.rawStderr) if abortMsgs is None and minimumSupportedVersion >= 13: # Look for auxiliary abort messages also inside crashdata # only on version 1.3 or higher, because the "crashdata" source # type for output matching was added in that version. abortMsgs = AssertionHelper.getAuxiliaryAbortMessage(self.rawCrashData) if abortMsgs != None: abortMsgInCrashdata = True if abortMsgs != None: if not isinstance(abortMsgs, list): abortMsgs = [abortMsgs] for abortMsg in abortMsgs: abortMsg = AssertionHelper.getSanitizedAssertionPattern(abortMsg) abortMsgSrc = "stderr" if abortMsgInCrashdata: abortMsgSrc = "crashdata" # Compose StringMatch object with PCRE pattern. # Versions below 1.2 only support the full object PCRE style, # for anything newer, use the short form with forward slashes # to increase the readability of the signatures. if minimumSupportedVersion < 12: stringObj = { "value" : abortMsg, "matchType" : "pcre" } symptomObj = { "type" : "output", "src" : abortMsgSrc, "value" : stringObj } else: symptomObj = { "type" : "output", "src" : abortMsgSrc, "value" : "/%s/" % abortMsg } symptomArr.append(symptomObj) # Consider the first four frames as top stack topStackLimit = 4 # If we have less than topStackLimit frames available anyway, count the difference # between topStackLimit and the available frames already as missing. # E.g. if the trace has only three entries anyway, one will be considered missing # right from the start. This should prevent that very short stack frames are used # for signatures without additional crash information that narrows the signature. if numFrames >= topStackLimit: topStackMissCount = 0 else: topStackMissCount = topStackLimit - numFrames # StackFramesSymptom is only supported in 1.2 and higher, # for everything else, use multiple stackFrame symptoms if minimumSupportedVersion < 12: for idx in range(0, numFrames): functionName = self.backtrace[idx] if not functionName == "??": symptomObj = { "type" : "stackFrame", "frameNumber" : idx, "functionName" : functionName } symptomArr.append(symptomObj) elif idx < 4: # If we're in the top 4, we count this as a miss topStackMissCount += 1 else: framesArray = [] for idx in range(0, numFrames): functionName = self.backtrace[idx] if not functionName == "??": framesArray.append(functionName) else: framesArray.append("?") if idx < 4: # If we're in the top 4, we count this as a miss topStackMissCount += 1 lastSymbolizedFrame = None for frameIdx in range(0, len(framesArray)): if str(framesArray[frameIdx]) != '?': lastSymbolizedFrame = frameIdx if lastSymbolizedFrame != None: # Remove all elements behind the last symbolized frame framesArray = framesArray[:lastSymbolizedFrame + 1] else: # We don't have a single symbolized frame, so it doesn't make sense # to keep any wildcards in case we added some for unsymbolized frames. framesArray = [] if framesArray: symptomArr.append({ "type" : "stackFrames", "functionNames" : framesArray }) # Missing too much of the top stack frames, add additional crash information stackIsInsufficient = topStackMissCount >= 2 and abortMsgs == None includeCrashAddress = stackIsInsufficient or forceCrashAddress includeCrashInstruction = (stackIsInsufficient and self.crashInstruction != None) or forceCrashInstruction if includeCrashAddress: if self.crashAddress == None: crashAddress = "" elif self.crashAddress != 0L and self.crashAddress < 0x100L: # Try to match crash addresses that are small but non-zero # with a generic range that is likely associated with null-deref. crashAddress = "< 0x100" else: crashAddress = hex(self.crashAddress).rstrip("L") crashAddressSymptomObj = { "type" : "crashAddress", "address" : crashAddress } symptomArr.append(crashAddressSymptomObj)
def createCrashSignature(self, forceCrashAddress=False, forceCrashInstruction=False, maxFrames=8, minimumSupportedVersion=13): ''' @param forceCrashAddress: If True, the crash address will be included in any case @type forceCrashAddress: bool @param forceCrashInstruction: If True, the crash instruction will be included in any case @type forceCrashInstruction: bool @param maxFrames: How many frames (at most) should be included in the signature @type maxFrames: int @param minimumSupportedVersion: The minimum crash signature standard version that the generated signature should be valid for (10 => 1.0, 13 => 1.3) @type minimumSupportedVersion: int @rtype: CrashSignature @return: A crash signature object ''' # Determine the actual number of frames based on how many we got if len(self.backtrace) > maxFrames: numFrames = maxFrames else: numFrames = len(self.backtrace) # See if we have an abort message and if so, get a sanitized version of it abortMsg = AssertionHelper.getAssertion(self.rawStderr, True) if abortMsg != None: abortMsg = AssertionHelper.getSanitizedAssertionPattern(abortMsg) # Consider the first four frames as top stack topStackLimit = 4 symptomArr = [] if abortMsg != None: # Compose StringMatch object with PCRE pattern. # Versions below 1.2 only support the full object PCRE style, # for anything newer, use the short form with forward slashes # to increase the readability of the signatures. if minimumSupportedVersion < 12: stringObj = { "value" : abortMsg, "matchType" : "pcre" } symptomObj = { "type" : "output", "src" : "stderr", "value" : stringObj } else: symptomObj = { "type" : "output", "src" : "stderr", "value" : "/%s/" % abortMsg } symptomArr.append(symptomObj) # If we have less than topStackLimit frames available anyway, count the difference # between topStackLimit and the available frames already as missing. # E.g. if the trace has only three entries anyway, one will be considered missing # right from the start. This should prevent that very short stack frames are used # for signatures without additional crash information that narrows the signature. if numFrames >= topStackLimit: topStackMissCount = 0 else: topStackMissCount = topStackLimit - numFrames # StackFramesSymptom is only supported in 1.2 and higher, # for everything else, use multiple stackFrame symptoms if minimumSupportedVersion < 12: for idx in range(0, numFrames): functionName = self.backtrace[idx] if not functionName == "??": symptomObj = { "type" : "stackFrame", "frameNumber" : idx, "functionName" : functionName } symptomArr.append(symptomObj) elif idx < 4: # If we're in the top 4, we count this as a miss topStackMissCount += 1 else: framesArray = [] for idx in range(0, numFrames): functionName = self.backtrace[idx] if not functionName == "??": framesArray.append(functionName) else: framesArray.append("?") if idx < 4: # If we're in the top 4, we count this as a miss topStackMissCount += 1 lastSymbolizedFrame = None for frameIdx in range(0, len(framesArray)): if str(framesArray[frameIdx]) != '?': lastSymbolizedFrame = frameIdx if lastSymbolizedFrame != None: # Remove all elements behind the last symbolized frame framesArray = framesArray[:lastSymbolizedFrame + 1] else: # We don't have a single symbolized frame, so it doesn't make sense # to keep any wildcards in case we added some for unsymbolized frames. framesArray = [] if framesArray: symptomArr.append({ "type" : "stackFrames", "functionNames" : framesArray }) # Missing too much of the top stack frames, add additional crash information stackIsInsufficient = topStackMissCount >= 2 and abortMsg == None includeCrashAddress = stackIsInsufficient or forceCrashAddress includeCrashInstruction = (stackIsInsufficient and self.crashInstruction != None) or forceCrashInstruction if includeCrashAddress: if self.crashAddress == None: failureReason = self.failureReason self.failureReason = "No crash address available from crash data. Reason: %s" % failureReason return None crashAddress = hex(self.crashAddress).rstrip("L") crashAddressSymptomObj = { "type" : "crashAddress", "address" : crashAddress } symptomArr.append(crashAddressSymptomObj) if includeCrashInstruction: if self.crashInstruction == None: failureReason = self.failureReason self.failureReason = "No crash instruction available from crash data. Reason: %s" % failureReason return None crashInstructionSymptomObj = { "type" : "instruction", "instructionName" : self.crashInstruction } symptomArr.append(crashInstructionSymptomObj) sigObj = { "symptoms" : symptomArr } return CrashSignature(json.dumps(sigObj, indent=2))