def createShortSignature(self): ''' @rtype: String @return: A string representing this crash (short signature) ''' # Always prefer using regular program aborts abortMsg = AssertionHelper.getAssertion(self.rawStderr) # Also check the crash data for program abort data # (sometimes happens e.g. with MOZ_CRASH) if not abortMsg and self.rawCrashData: abortMsg = AssertionHelper.getAssertion(self.rawCrashData) if abortMsg != None: if isinstance(abortMsg, list): return " ".join(abortMsg) else: return abortMsg # If we don't have a program abort message, see if we have an ASan # specific abort message other than a crash message that we can use. abortMsg = AssertionHelper.getAuxiliaryAbortMessage(self.rawStderr) # Also check the crash data again if not abortMsg and self.rawCrashData: abortMsg = AssertionHelper.getAuxiliaryAbortMessage(self.rawCrashData) if abortMsg != None: rwMsg = None if isinstance(abortMsg, list): asanMsg = abortMsg[0] rwMsg = abortMsg[1] else: asanMsg = abortMsg # Do some additional formatting work for short signature only asanMsg = re.sub("^ERROR: ", "", asanMsg) # Strip various forms of special thread information and messages asanMsg = re.sub(" in thread T.+", "", asanMsg) asanMsg = re.sub(" malloc\(\)\-ed: 0x[0-9a-f]+", r" malloc()-ed", asanMsg) if len(self.backtrace): asanMsg += " [@ %s]" % self.backtrace[0] if rwMsg: # Strip address and thread rwMsg = re.sub(" at 0x[0-9a-f]+ thread .+", "", rwMsg) asanMsg += " with %s" % rwMsg return asanMsg if not len(self.backtrace): return "No crash detected" return "[@ %s]" % self.backtrace[0]
def runTest(self): err = asanStackOverflow.splitlines() assert AssertionHelper.getAssertion(err) is None assertMsg = AssertionHelper.getAuxiliaryAbortMessage(err) expectedAssertMsg = "ERROR: AddressSanitizer: stack-overflow" assert assertMsg == expectedAssertMsg
def test_AssertionHelperTestASanStackOverflow(): err = asanStackOverflow.splitlines() assert AssertionHelper.getAssertion(err) is None assertMsg = AssertionHelper.getAuxiliaryAbortMessage(err) expectedAssertMsg = "ERROR: AddressSanitizer: stack-overflow" assert assertMsg == expectedAssertMsg
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 = asanStackOverflow.splitlines() self.assertEqual(AssertionHelper.getAssertion(err), None) assertMsg = AssertionHelper.getAuxiliaryAbortMessage(err) expectedAssertMsg = "ERROR: AddressSanitizer: stack-overflow" self.assertEqual(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 = 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 = 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 = [ "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 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 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 createShortSignature(self): ''' @rtype: String @return: A string representing this crash (short signature) ''' # Try to find the UBSan message on stderr and use that as short signature abortMsg = AssertionHelper.getAuxiliaryAbortMessage(self.rawStderr) # See if we have it in our crash data maybe instead if not abortMsg and self.rawCrashData: abortMsg = AssertionHelper.getAuxiliaryAbortMessage(self.rawCrashData) if abortMsg != None: if isinstance(abortMsg, list): return "UndefinedBehaviorSanitizer: %s" % " ".join(abortMsg) else: return "UndefinedBehaviorSanitizer: %s" % abortMsg if not len(self.backtrace): return "No crash detected" return "UndefinedBehaviorSanitizer: [@ %s]" % self.backtrace[0]
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) # Ensure the sanitized messages can be compiled as regex without errors re.compile(sanitizedMsg[0]) re.compile(sanitizedMsg[1])
def test_AssertionHelperTestASanFFAbort(): err = asanFFAbort.splitlines() assert AssertionHelper.getAssertion(err) is None assert AssertionHelper.getAuxiliaryAbortMessage(err) is None
def runTest(self): err = asanFFAbort.splitlines() assert AssertionHelper.getAssertion(err) is None assert AssertionHelper.getAuxiliaryAbortMessage(err) is None
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 runTest(self): err = asanFFAbort.splitlines() self.assertEqual(AssertionHelper.getAssertion(err), None) self.assertEqual(AssertionHelper.getAuxiliaryAbortMessage(err), None)
def runTest(self): err = asanFFAbort.splitlines() self.assertEqual(AssertionHelper.getAssertion(err), None) self.assertEqual(AssertionHelper.getAuxiliaryAbortMessage(err), None)
def runTest(self): err = asanFFAbort.splitlines() assert AssertionHelper.getAssertion(err) is None assert AssertionHelper.getAuxiliaryAbortMessage(err) is None