Back to index

apport  2.4
Public Member Functions | Private Member Functions
test_report.T Class Reference

List of all members.

Public Member Functions

def test_add_package_info
def test_add_os_info
def test_add_user_info
def test_add_proc_info
def test_add_path_classification
def test_check_interpreted
def test_check_interpreted_twistd
def test_add_gdb_info
def test_add_gdb_info_load
def test_add_zz_parse_segv_details
def test_add_gdb_info_script
def test_add_gdb_info_abort
def test_search_bug_patterns
def test_add_hooks_info
def test_ignoring
def test_blacklisting
def test_whitelisting
def test_has_useful_stacktrace
def test_standard_title
def test_obsolete_packages
def test_gen_stacktrace_top
def test_crash_signature
def test_nonascii_data
def test_address_to_offset
def test_address_to_offset_live
def test_crash_signature_addresses

Private Member Functions

def _generate_sigsegv_report
def _validate_core
def _validate_gdb_fields

Detailed Description

Definition at line 9 of file test_report.py.


Member Function Documentation

def test_report.T._generate_sigsegv_report (   klass,
  file = None,
  signal = '11',
  code = ''' int f(x) { int* p = 0; *p = x; return x+1; } int main() { return f(42); } ''' 
) [private]
Create a test executable which will die with a SIGSEGV, generate a
core dump for it, create a problem report with those two arguments
(ExecutablePath and CoreDump) and call add_gdb_info().

If file is given, the report is written into it. Return the apport.report.Report.

Definition at line 430 of file test_report.py.

00430 
00431 '''):
00432         '''Create a test executable which will die with a SIGSEGV, generate a
00433         core dump for it, create a problem report with those two arguments
00434         (ExecutablePath and CoreDump) and call add_gdb_info().
00435 
00436         If file is given, the report is written into it. Return the apport.report.Report.'''
00437 
00438         workdir = None
00439         orig_cwd = os.getcwd()
00440         pr = apport.report.Report()
00441         try:
00442             workdir = tempfile.mkdtemp()
00443             atexit.register(shutil.rmtree, workdir)
00444             os.chdir(workdir)
00445 
00446             # create a test executable
00447             with open('crash.c', 'w') as fd:
00448                 fd.write(code)
00449             assert subprocess.call(['gcc', '-g', 'crash.c', '-o', 'crash']) == 0
00450             assert os.path.exists('crash')
00451 
00452             # call it through gdb and dump core
00453             gdb = subprocess.Popen(['gdb', '--batch', '--ex', 'run', '--ex',
00454                                     'generate-core-file core', './crash'], stdout=subprocess.PIPE)
00455             gdb.communicate()
00456             klass._validate_core('core')
00457 
00458             pr['ExecutablePath'] = os.path.join(workdir, 'crash')
00459             pr['CoreDump'] = (os.path.join(workdir, 'core'),)
00460             pr['Signal'] = signal
00461 
00462             pr.add_gdb_info()
00463             if file:
00464                 pr.write(file)
00465                 file.flush()
00466         finally:
00467             os.chdir(orig_cwd)
00468 
00469         return pr

Here is the caller graph for this function:

def test_report.T._validate_core (   klass,
  core_path 
) [private]

Definition at line 471 of file test_report.py.

00471 
00472     def _validate_core(klass, core_path):
00473         subprocess.check_call(['sync'])
00474         assert os.path.exists(core_path)
00475         readelf = subprocess.Popen(['readelf', '-n', core_path], stdout=subprocess.PIPE)
00476         readelf.communicate()
00477         assert readelf.returncode == 0

def test_report.T._validate_gdb_fields (   self,
  pr 
) [private]

Definition at line 478 of file test_report.py.

00478 
00479     def _validate_gdb_fields(self, pr):
00480         self.assertTrue('Stacktrace' in pr)
00481         self.assertTrue('ThreadStacktrace' in pr)
00482         self.assertTrue('StacktraceTop' in pr)
00483         self.assertTrue('Registers' in pr)
00484         self.assertTrue('Disassembly' in pr)
00485         self.assertTrue('(no debugging symbols found)' not in pr['Stacktrace'])
00486         self.assertTrue('Core was generated by' not in pr['Stacktrace'], pr['Stacktrace'])
00487         self.assertTrue(not re.match(r'(?s)(^|.*\n)#0  [^\n]+\n#0  ',
00488                                      pr['Stacktrace']))
00489         self.assertTrue('#0  0x' in pr['Stacktrace'])
00490         self.assertTrue('#1  0x' in pr['Stacktrace'])
00491         self.assertTrue('#0  0x' in pr['ThreadStacktrace'])
00492         self.assertTrue('#1  0x' in pr['ThreadStacktrace'])
00493         self.assertTrue('Thread 1 (' in pr['ThreadStacktrace'])
00494         self.assertTrue(len(pr['StacktraceTop'].splitlines()) <= 5)

add_gdb_info() with core dump file reference.

Definition at line 495 of file test_report.py.

00495 
00496     def test_add_gdb_info(self):
00497         '''add_gdb_info() with core dump file reference.'''
00498 
00499         pr = apport.report.Report()
00500         # should not throw an exception for missing fields
00501         pr.add_gdb_info()
00502 
00503         # normal crash
00504         pr = self._generate_sigsegv_report()
00505         self._validate_gdb_fields(pr)
00506         self.assertEqual(pr['StacktraceTop'], 'f (x=42) at crash.c:3\nmain () at crash.c:6', pr['StacktraceTop'])
00507         self.assertFalse('AssertionMessage' in pr)
00508 
00509         # crash where gdb generates output on stderr
00510         pr = self._generate_sigsegv_report(code='''
00511 int main() {
00512     void     (*function)(void);
00513     function = 0;
00514     function();
00515 }
00516 ''')
00517         self._validate_gdb_fields(pr)
00518         self.assertTrue('Cannot access memory at address 0x0' in pr['Disassembly'], pr['Disassembly'])
00519         self.assertFalse('AssertionMessage' in pr)

Here is the call graph for this function:

add_gdb_info() with SIGABRT/assert()

If these come from an assert(), the report should have the assertion
message. Otherwise it should be marked as not reportable.

Definition at line 598 of file test_report.py.

00598 
00599     def test_add_gdb_info_abort(self):
00600         '''add_gdb_info() with SIGABRT/assert()
00601 
00602         If these come from an assert(), the report should have the assertion
00603         message. Otherwise it should be marked as not reportable.
00604         '''
00605         # abort with assert
00606         (fd, script) = tempfile.mkstemp()
00607         assert not os.path.exists('core')
00608         try:
00609             os.close(fd)
00610 
00611             # create a test script which produces a core dump for us
00612             with open(script, 'w') as fd:
00613                 fd.write('''#!/bin/sh
00614 gcc -o $0.bin -x c - <<EOF
00615 #include <assert.h>
00616 int main() { assert(1 < 0); }
00617 EOF
00618 ulimit -c unlimited
00619 $0.bin 2>/dev/null
00620 ''')
00621             os.chmod(script, 0o755)
00622 
00623             # call script and verify that it gives us a proper ELF core dump
00624             assert subprocess.call([script]) != 0
00625             self._validate_core('core')
00626 
00627             pr = apport.report.Report()
00628             pr['ExecutablePath'] = script + '.bin'
00629             pr['CoreDump'] = ('core',)
00630             pr.add_gdb_info()
00631         finally:
00632             os.unlink(script)
00633             os.unlink(script + '.bin')
00634             os.unlink('core')
00635 
00636         self._validate_gdb_fields(pr)
00637         self.assertTrue("<stdin>:2: main: Assertion `1 < 0' failed." in
00638                         pr['AssertionMessage'], pr['AssertionMessage'])
00639         self.assertFalse(pr['AssertionMessage'].startswith('$'), pr['AssertionMessage'])
00640         self.assertFalse('= 0x' in pr['AssertionMessage'], pr['AssertionMessage'])
00641         self.assertFalse(pr['AssertionMessage'].endswith('\\n'), pr['AssertionMessage'])
00642 
00643         # abort with internal error
00644         (fd, script) = tempfile.mkstemp()
00645         assert not os.path.exists('core')
00646         try:
00647             os.close(fd)
00648 
00649             # create a test script which produces a core dump for us
00650             with open(script, 'w') as fd:
00651                 fd.write('''#!/bin/sh
00652 gcc -O2 -D_FORTIFY_SOURCE=2 -o $0.bin -x c - <<EOF
00653 #include <string.h>
00654 int main(int argc, char *argv[]) {
00655     char buf[8];
00656     strcpy(buf, argv[1]);
00657     return 0;
00658 }
00659 EOF
00660 ulimit -c unlimited
00661 LIBC_FATAL_STDERR_=1 $0.bin aaaaaaaaaaaaaaaa 2>/dev/null
00662 ''')
00663             os.chmod(script, 0o755)
00664 
00665             # call script and verify that it gives us a proper ELF core dump
00666             assert subprocess.call([script]) != 0
00667             self._validate_core('core')
00668 
00669             pr = apport.report.Report()
00670             pr['ExecutablePath'] = script + '.bin'
00671             pr['CoreDump'] = ('core',)
00672             pr.add_gdb_info()
00673         finally:
00674             os.unlink(script)
00675             os.unlink(script + '.bin')
00676             os.unlink('core')
00677 
00678         self._validate_gdb_fields(pr)
00679         self.assertTrue("** buffer overflow detected ***: %s.bin terminated" % (script) in
00680                         pr['AssertionMessage'], pr['AssertionMessage'])
00681         self.assertFalse(pr['AssertionMessage'].startswith('$'), pr['AssertionMessage'])
00682         self.assertFalse('= 0x' in pr['AssertionMessage'], pr['AssertionMessage'])
00683         self.assertFalse(pr['AssertionMessage'].endswith('\\n'), pr['AssertionMessage'])
00684 
00685         # abort without assertion
00686         (fd, script) = tempfile.mkstemp()
00687         assert not os.path.exists('core')
00688         try:
00689             os.close(fd)
00690 
00691             # create a test script which produces a core dump for us
00692             with open(script, 'w') as fd:
00693                 fd.write('''#!/bin/sh
00694 gcc -o $0.bin -x c - <<EOF
00695 #include <stdlib.h>
00696 int main() { abort(); }
00697 EOF
00698 ulimit -c unlimited
00699 $0.bin 2>/dev/null
00700 ''')
00701             os.chmod(script, 0o755)
00702 
00703             # call script and verify that it gives us a proper ELF core dump
00704             assert subprocess.call([script]) != 0
00705             self._validate_core('core')
00706 
00707             pr = apport.report.Report()
00708             pr['ExecutablePath'] = script + '.bin'
00709             pr['CoreDump'] = ('core',)
00710             pr.add_gdb_info()
00711         finally:
00712             os.unlink(script)
00713             os.unlink(script + '.bin')
00714             os.unlink('core')
00715 
00716         self._validate_gdb_fields(pr)
00717         self.assertFalse('AssertionMessage' in pr, pr.get('AssertionMessage'))

Here is the call graph for this function:

add_gdb_info() with inline core dump.

Definition at line 520 of file test_report.py.

00520 
00521     def test_add_gdb_info_load(self):
00522         '''add_gdb_info() with inline core dump.'''
00523 
00524         rep = tempfile.NamedTemporaryFile()
00525         self._generate_sigsegv_report(rep)
00526         rep.seek(0)
00527 
00528         pr = apport.report.Report()
00529         with open(rep.name, 'rb') as f:
00530             pr.load(f)
00531         pr.add_gdb_info()
00532 
00533         self._validate_gdb_fields(pr)

Here is the call graph for this function:

add_gdb_info() with a script.

Definition at line 564 of file test_report.py.

00564 
00565     def test_add_gdb_info_script(self):
00566         '''add_gdb_info() with a script.'''
00567 
00568         (fd, script) = tempfile.mkstemp()
00569         coredump = os.path.join(os.path.dirname(script), 'core')
00570         assert not os.path.exists(coredump)
00571         try:
00572             os.close(fd)
00573 
00574             # create a test script which produces a core dump for us
00575             with open(script, 'w') as fd:
00576                 fd.write('''#!/bin/bash
00577 cd `dirname $0`
00578 ulimit -c unlimited
00579 kill -SEGV $$
00580 ''')
00581             os.chmod(script, 0o755)
00582 
00583             # call script and verify that it gives us a proper ELF core dump
00584             assert subprocess.call([script]) != 0
00585             self._validate_core(coredump)
00586 
00587             pr = apport.report.Report()
00588             pr['InterpreterPath'] = '/bin/bash'
00589             pr['ExecutablePath'] = script
00590             pr['CoreDump'] = (coredump,)
00591             pr.add_gdb_info()
00592         finally:
00593             os.unlink(coredump)
00594             os.unlink(script)
00595 
00596         self._validate_gdb_fields(pr)
00597         self.assertTrue('libc.so' in pr['Stacktrace'] or 'in execute_command' in pr['Stacktrace'])

Here is the call graph for this function:

add_hooks_info().

Definition at line 828 of file test_report.py.

00828 
00829     def test_add_hooks_info(self):
00830         '''add_hooks_info().'''
00831 
00832         orig_hook_dir = apport.report._hook_dir
00833         apport.report._hook_dir = tempfile.mkdtemp()
00834         orig_common_hook_dir = apport.report._common_hook_dir
00835         apport.report._common_hook_dir = tempfile.mkdtemp()
00836         try:
00837             with open(os.path.join(apport.report._hook_dir, 'foo.py'), 'w') as fd:
00838                 fd.write('''
00839 import sys
00840 def add_info(report):
00841     report['Field1'] = 'Field 1'
00842     report['Field2'] = 'Field 2\\nBla'
00843     if 'Spethial' in report:
00844         raise StopIteration
00845 ''')
00846 
00847             with open(os.path.join(apport.report._common_hook_dir, 'foo1.py'), 'w') as fd:
00848                 fd.write('''
00849 def add_info(report):
00850     report['CommonField1'] = 'CommonField 1'
00851     if report['Package'] == 'commonspethial':
00852         raise StopIteration
00853 ''')
00854             with open(os.path.join(apport.report._common_hook_dir, 'foo2.py'), 'w') as fd:
00855                 fd.write('''
00856 def add_info(report):
00857     report['CommonField2'] = 'CommonField 2'
00858 ''')
00859             with open(os.path.join(apport.report._common_hook_dir, 'foo3.py'), 'w') as fd:
00860                 fd.write('''
00861 def add_info(report, ui):
00862     report['CommonField3'] = str(ui)
00863 ''')
00864 
00865             # should only catch .py files
00866             with open(os.path.join(apport.report._common_hook_dir, 'notme'), 'w') as fd:
00867                 fd.write('''
00868 def add_info(report):
00869     report['BadField'] = 'XXX'
00870 ''')
00871             r = apport.report.Report()
00872             r['Package'] = 'bar'
00873             # should not throw any exceptions
00874             self.assertEqual(r.add_hooks_info('fake_ui'), False)
00875             self.assertEqual(set(r.keys()),
00876                              set(['ProblemType', 'Date', 'Package',
00877                                   'CommonField1', 'CommonField2',
00878                                   'CommonField3']),
00879                              'report has required fields')
00880 
00881             r = apport.report.Report()
00882             r['Package'] = 'baz 1.2-3'
00883             # should not throw any exceptions
00884             self.assertEqual(r.add_hooks_info('fake_ui'), False)
00885             self.assertEqual(set(r.keys()),
00886                              set(['ProblemType', 'Date', 'Package',
00887                                   'CommonField1', 'CommonField2',
00888                                   'CommonField3']),
00889                              'report has required fields')
00890 
00891             r = apport.report.Report()
00892             r['Package'] = 'foo'
00893             self.assertEqual(r.add_hooks_info('fake_ui'), False)
00894             self.assertEqual(set(r.keys()),
00895                              set(['ProblemType', 'Date', 'Package', 'Field1',
00896                                   'Field2', 'CommonField1', 'CommonField2',
00897                                   'CommonField3']),
00898                              'report has required fields')
00899             self.assertEqual(r['Field1'], 'Field 1')
00900             self.assertEqual(r['Field2'], 'Field 2\nBla')
00901             self.assertEqual(r['CommonField1'], 'CommonField 1')
00902             self.assertEqual(r['CommonField2'], 'CommonField 2')
00903             self.assertEqual(r['CommonField3'], 'fake_ui')
00904 
00905             r = apport.report.Report()
00906             r['Package'] = 'foo 4.5-6'
00907             self.assertEqual(r.add_hooks_info('fake_ui'), False)
00908             self.assertEqual(set(r.keys()),
00909                              set(['ProblemType', 'Date', 'Package', 'Field1',
00910                                   'Field2', 'CommonField1', 'CommonField2',
00911                                   'CommonField3']),
00912                              'report has required fields')
00913             self.assertEqual(r['Field1'], 'Field 1')
00914             self.assertEqual(r['Field2'], 'Field 2\nBla')
00915             self.assertEqual(r['CommonField1'], 'CommonField 1')
00916             self.assertEqual(r['CommonField2'], 'CommonField 2')
00917 
00918             # test hook abort
00919             r['Spethial'] = '1'
00920             self.assertEqual(r.add_hooks_info('fake_ui'), True)
00921             r = apport.report.Report()
00922             r['Package'] = 'commonspethial'
00923             self.assertEqual(r.add_hooks_info('fake_ui'), True)
00924 
00925             # source package hook
00926             with open(os.path.join(apport.report._hook_dir, 'source_foo.py'), 'w') as fd:
00927                 fd.write('''
00928 def add_info(report, ui):
00929     report['Field1'] = 'Field 1'
00930     report['Field2'] = 'Field 2\\nBla'
00931     if report['Package'] == 'spethial':
00932         raise StopIteration
00933 ''')
00934             r = apport.report.Report()
00935             r['SourcePackage'] = 'foo'
00936             r['Package'] = 'libfoo 3'
00937             self.assertEqual(r.add_hooks_info('fake_ui'), False)
00938             self.assertEqual(set(r.keys()),
00939                              set(['ProblemType', 'Date', 'Package',
00940                                   'SourcePackage', 'Field1', 'Field2',
00941                                   'CommonField1', 'CommonField2',
00942                                   'CommonField3']),
00943                              'report has required fields')
00944             self.assertEqual(r['Field1'], 'Field 1')
00945             self.assertEqual(r['Field2'], 'Field 2\nBla')
00946             self.assertEqual(r['CommonField1'], 'CommonField 1')
00947             self.assertEqual(r['CommonField2'], 'CommonField 2')
00948             self.assertEqual(r['CommonField3'], 'fake_ui')
00949 
00950             # test hook abort
00951             r['Package'] = 'spethial'
00952             self.assertEqual(r.add_hooks_info('fake_ui'), True)
00953 
00954         finally:
00955             shutil.rmtree(apport.report._hook_dir)
00956             shutil.rmtree(apport.report._common_hook_dir)
00957             apport.report._hook_dir = orig_hook_dir
00958             apport.report._common_hook_dir = orig_common_hook_dir

Here is the call graph for this function:

add_os_info().

Definition at line 41 of file test_report.py.

00041 
00042     def test_add_os_info(self):
00043         '''add_os_info().'''
00044 
00045         pr = apport.report.Report()
00046         pr.add_os_info()
00047         self.assertTrue(pr['Uname'].startswith('Linux'))
00048         self.assertTrue(hasattr(pr['DistroRelease'], 'startswith'))
00049         self.assertGreater(len(pr['DistroRelease']), 5)
00050         self.assertTrue(pr['Architecture'])

add_package_info().

Definition at line 10 of file test_report.py.

00010 
00011     def test_add_package_info(self):
00012         '''add_package_info().'''
00013 
00014         # determine bash version
00015         bashversion = apport.packaging.get_version('bash')
00016 
00017         pr = apport.report.Report()
00018         self.assertRaises(ValueError, pr.add_package_info, 'nonexistant_package')
00019 
00020         pr.add_package_info('bash')
00021         self.assertEqual(pr['Package'], 'bash ' + bashversion.strip())
00022         self.assertEqual(pr['SourcePackage'], 'bash')
00023         self.assertTrue('libc' in pr['Dependencies'])
00024 
00025         # test without specifying a package, but with ExecutablePath
00026         pr = apport.report.Report()
00027         self.assertRaises(KeyError, pr.add_package_info)
00028         pr['ExecutablePath'] = '/bin/bash'
00029         pr.add_package_info()
00030         self.assertEqual(pr['Package'], 'bash ' + bashversion.strip())
00031         self.assertEqual(pr['SourcePackage'], 'bash')
00032         self.assertTrue('libc' in pr['Dependencies'])
00033         # check for stray empty lines
00034         self.assertTrue('\n\n' not in pr['Dependencies'])
00035         self.assertTrue('PackageArchitecture' in pr)
00036 
00037         pr = apport.report.Report()
00038         pr['ExecutablePath'] = '/nonexisting'
00039         pr.add_package_info()
00040         self.assertTrue('Package' not in pr)

classification of $PATH.

Definition at line 197 of file test_report.py.

00197 
00198     def test_add_path_classification(self):
00199         '''classification of $PATH.'''
00200 
00201         # system default
00202         p = subprocess.Popen(['cat'], stdin=subprocess.PIPE,
00203                              env={'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games'})
00204         time.sleep(0.1)
00205         r = apport.report.Report()
00206         r.add_proc_environ(pid=p.pid)
00207         p.communicate(b'')
00208         self.assertFalse('PATH' in r['ProcEnviron'],
00209                          'system default $PATH should be filtered out')
00210 
00211         # no user paths
00212         p = subprocess.Popen(['cat'], stdin=subprocess.PIPE,
00213                              env={'PATH': '/usr/sbin:/usr/bin:/sbin:/bin'})
00214         time.sleep(0.1)
00215         r = apport.report.Report()
00216         r.add_proc_environ(pid=p.pid)
00217         p.communicate(b'')
00218         self.assertTrue('PATH=(custom, no user)' in r['ProcEnviron'],
00219                         'PATH is customized without user paths')
00220 
00221         # user paths
00222         p = subprocess.Popen(['cat'], stdin=subprocess.PIPE,
00223                              env={'PATH': '/home/pitti:/usr/sbin:/usr/bin:/sbin:/bin'})
00224         time.sleep(0.1)
00225         r = apport.report.Report()
00226         r.add_proc_environ(pid=p.pid)
00227         p.communicate(b'')
00228         self.assertTrue('PATH=(custom, user)' in r['ProcEnviron'],
00229                         'PATH is customized with user paths')

add_proc_info().

Definition at line 63 of file test_report.py.

00063 
00064     def test_add_proc_info(self):
00065         '''add_proc_info().'''
00066 
00067         # set test environment
00068         assert 'LANG' in os.environ, 'please set $LANG for this test'
00069 
00070         # check without additional safe environment variables
00071         pr = apport.report.Report()
00072         self.assertEqual(pr.pid, None)
00073         pr.add_proc_info()
00074         self.assertEqual(pr.pid, os.getpid())
00075         self.assertTrue(set(['ProcEnviron', 'ProcMaps', 'ProcCmdline',
00076                              'ProcMaps']).issubset(set(pr.keys())), 'report has required fields')
00077         self.assertTrue('LANG=' + os.environ['LANG'] in pr['ProcEnviron'])
00078         self.assertTrue('USER' not in pr['ProcEnviron'])
00079         self.assertTrue('PWD' not in pr['ProcEnviron'])
00080         self.assertTrue('report.py' in pr['ExecutablePath'])
00081         self.assertEqual(int(pr['ExecutableTimestamp']),
00082                          int(os.stat(__file__).st_mtime))
00083 
00084         # check with one additional safe environment variable
00085         pr = apport.report.Report()
00086         pr.add_proc_info(extraenv=['PWD'])
00087         self.assertTrue('USER' not in pr['ProcEnviron'])
00088         if 'PWD' in os.environ:
00089             self.assertTrue('PWD=' + os.environ['PWD'] in pr['ProcEnviron'])
00090 
00091         # check process from other user
00092         restore_root = False
00093         if os.getuid() == 0:
00094             # temporarily drop to normal user "mail"
00095             os.setresuid(8, 8, -1)
00096             restore_root = True
00097         pr = apport.report.Report()
00098         self.assertRaises(OSError, pr.add_proc_info, 1)  # EPERM for init process
00099         if restore_root:
00100             os.setresuid(0, 0, -1)
00101 
00102         self.assertEqual(pr.pid, 1)
00103         self.assertTrue('init' in pr['ProcStatus'], pr['ProcStatus'])
00104         self.assertTrue(pr['ProcEnviron'].startswith('Error:'), pr['ProcEnviron'])
00105         self.assertTrue('InterpreterPath' not in pr)
00106 
00107         # check escaping of ProcCmdline
00108         p = subprocess.Popen(['cat', '/foo bar', '\\h', '\\ \\', '-'],
00109                              stdin=subprocess.PIPE, stdout=subprocess.PIPE,
00110                              stderr=subprocess.PIPE)
00111         assert p.pid
00112         # wait until /proc/pid/cmdline exists
00113         while True:
00114             with open('/proc/%i/cmdline' % p.pid) as fd:
00115                 if fd.read():
00116                     break
00117                 time.sleep(0.1)
00118         pr = apport.report.Report()
00119         pr.add_proc_info(pid=p.pid)
00120         self.assertEqual(pr.pid, p.pid)
00121         p.communicate(b'\n')
00122         self.assertEqual(pr['ProcCmdline'], 'cat /foo\ bar \\\\h \\\\\\ \\\\ -')
00123         self.assertEqual(pr['ExecutablePath'], '/bin/cat')
00124         self.assertTrue('InterpreterPath' not in pr)
00125         self.assertTrue('/bin/cat' in pr['ProcMaps'])
00126         self.assertTrue('[stack]' in pr['ProcMaps'])
00127 
00128         # check correct handling of executable symlinks
00129         assert os.path.islink('/bin/sh'), '/bin/sh needs to be a symlink for this test'
00130         p = subprocess.Popen(['sh'], stdin=subprocess.PIPE)
00131         assert p.pid
00132         # wait until /proc/pid/cmdline exists
00133         while True:
00134             with open('/proc/%i/cmdline' % p.pid) as fd:
00135                 if fd.read():
00136                     break
00137                 time.sleep(0.1)
00138         pr = apport.report.Report()
00139         pr.pid = p.pid
00140         pr.add_proc_info()
00141         p.communicate(b'exit\n')
00142         self.assertFalse('InterpreterPath' in pr, pr.get('InterpreterPath'))
00143         self.assertEqual(pr['ExecutablePath'], os.path.realpath('/bin/sh'))
00144         self.assertEqual(int(pr['ExecutableTimestamp']),
00145                          int(os.stat(os.path.realpath('/bin/sh')).st_mtime))
00146 
00147         # check correct handling of interpreted executables: shell
00148         p = subprocess.Popen(['zgrep', 'foo'], stdin=subprocess.PIPE)
00149         assert p.pid
00150         # wait until /proc/pid/cmdline exists
00151         while True:
00152             with open('/proc/%i/cmdline' % p.pid) as fd:
00153                 if fd.read():
00154                     break
00155                 time.sleep(0.1)
00156         pr = apport.report.Report()
00157         pr.add_proc_info(pid=p.pid)
00158         p.communicate(b'\n')
00159         self.assertTrue(pr['ExecutablePath'].endswith('bin/zgrep'))
00160         with open(pr['ExecutablePath']) as fd:
00161             self.assertEqual(pr['InterpreterPath'],
00162                              os.path.realpath(fd.readline().strip()[2:]))
00163         self.assertEqual(int(pr['ExecutableTimestamp']),
00164                          int(os.stat(pr['ExecutablePath']).st_mtime))
00165         self.assertTrue('[stack]' in pr['ProcMaps'])
00166 
00167         # check correct handling of interpreted executables: python
00168         (fd, testscript) = tempfile.mkstemp()
00169         os.write(fd, ('''#!/usr/bin/%s
00170 import sys
00171 sys.stdin.readline()
00172 ''' % os.getenv('PYTHON', 'python3')).encode('ascii'))
00173         os.close(fd)
00174         os.chmod(testscript, 0o755)
00175         p = subprocess.Popen([testscript], stdin=subprocess.PIPE,
00176                              stderr=subprocess.PIPE)
00177         assert p.pid
00178         # wait until /proc/pid/cmdline exists
00179         while True:
00180             with open('/proc/%i/cmdline' % p.pid) as fd:
00181                 if fd.read():
00182                     break
00183                 time.sleep(0.1)
00184         pr = apport.report.Report()
00185         pr.add_proc_info(pid=p.pid)
00186         p.communicate(b'\n')
00187         self.assertEqual(pr['ExecutablePath'], testscript)
00188         self.assertEqual(int(pr['ExecutableTimestamp']),
00189                          int(os.stat(testscript).st_mtime))
00190         os.unlink(testscript)
00191         self.assertTrue('python' in pr['InterpreterPath'])
00192         self.assertTrue('python' in pr['ProcMaps'])
00193         self.assertTrue('[stack]' in pr['ProcMaps'])
00194 
00195         # test process is gone, should complain about nonexisting PID
00196         self.assertRaises(ValueError, pr.add_proc_info, p.pid)

add_user_info().

Definition at line 51 of file test_report.py.

00051 
00052     def test_add_user_info(self):
00053         '''add_user_info().'''
00054 
00055         pr = apport.report.Report()
00056         pr.add_user_info()
00057         self.assertTrue('UserGroups' in pr)
00058 
00059         # double-check that user group names are removed
00060         for g in pr['UserGroups'].split():
00061             self.assertTrue(grp.getgrnam(g).gr_gid < 1000)
00062         self.assertTrue(grp.getgrgid(os.getgid()).gr_name not in pr['UserGroups'])

parse-segv produces sensible results

Definition at line 534 of file test_report.py.

00534 
00535     def test_add_zz_parse_segv_details(self):
00536         '''parse-segv produces sensible results'''
00537         rep = tempfile.NamedTemporaryFile()
00538         self._generate_sigsegv_report(rep)
00539         rep.seek(0)
00540 
00541         pr = apport.report.Report()
00542         with open(rep.name, 'rb') as f:
00543             pr.load(f)
00544         pr['Signal'] = '1'
00545         pr.add_hooks_info('fake_ui')
00546         self.assertTrue('SegvAnalysis' not in pr.keys())
00547 
00548         pr = apport.report.Report()
00549         with open(rep.name, 'rb') as f:
00550             pr.load(f)
00551         pr.add_hooks_info('fake_ui')
00552         self.assertTrue('Skipped: missing required field "Architecture"' in pr['SegvAnalysis'],
00553                         pr['SegvAnalysis'])
00554 
00555         pr.add_os_info()
00556         pr.add_hooks_info('fake_ui')
00557         self.assertTrue('Skipped: missing required field "ProcMaps"' in pr['SegvAnalysis'],
00558                         pr['SegvAnalysis'])
00559 
00560         pr.add_proc_info()
00561         pr.add_hooks_info('fake_ui')
00562         self.assertTrue('not located in a known VMA region' in pr['SegvAnalysis'],
00563                         pr['SegvAnalysis'])

Here is the call graph for this function:

_address_to_offset()

Definition at line 1695 of file test_report.py.

01695 
01696     def test_address_to_offset(self):
01697         '''_address_to_offset()'''
01698 
01699         pr = apport.report.Report()
01700 
01701         self.assertRaises(AssertionError, pr._address_to_offset, 0)
01702 
01703         pr['ProcMaps'] = '''
01704 00400000-004df000 r-xp 00000000 08:02 1044485                            /bin/bash
01705 006de000-006df000 r--p 000de000 08:02 1044485                            /bin/bash
01706 01596000-01597000 rw-p 00000000 00:00 0
01707 01597000-015a4000 rw-p 00000000 00:00 0                                  [heap]
01708 7f491f868000-7f491f88a000 r-xp 00000000 08:02 526219                     /lib/x86_64-linux-gnu/libtinfo.so.5.9
01709 7f491fa8f000-7f491fc24000 r-xp 00000000 08:02 522605                     /lib/x86_64-linux-gnu/libc-2.13.so
01710 7f491fc24000-7f491fe23000 ---p 00195000 08:02 522605                     /lib/with spaces !/libfoo.so
01711 7fff6e57b000-7fff6e59c000 rw-p 00000000 00:00 0                          [stack]
01712 7fff6e5ff000-7fff6e600000 r-xp 00000000 00:00 0                          [vdso]
01713 ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
01714 '''
01715 
01716         self.assertEqual(pr._address_to_offset(0x41d703), '/bin/bash+1d703')
01717         self.assertEqual(pr._address_to_offset(0x00007f491fac5687),
01718                          '/lib/x86_64-linux-gnu/libc-2.13.so+36687')
01719 
01720         self.assertEqual(pr._address_to_offset(0x006ddfff), None)
01721         self.assertEqual(pr._address_to_offset(0x006de000), '/bin/bash+0')
01722         self.assertEqual(pr._address_to_offset(0x006df000), '/bin/bash+1000')
01723         self.assertEqual(pr._address_to_offset(0x006df001), None)
01724 
01725         self.assertEqual(pr._address_to_offset(0x7f491fc24010),
01726                          '/lib/with spaces !/libfoo.so+10')

_address_to_offset() for current /proc/pid/maps

Definition at line 1727 of file test_report.py.

01727 
01728     def test_address_to_offset_live(self):
01729         '''_address_to_offset() for current /proc/pid/maps'''
01730 
01731         # this primarily checks that the parser actually gets along with the
01732         # real /proc/pid/maps and not just with our static test case above
01733         pr = apport.report.Report()
01734         pr.add_proc_info()
01735         self.assertEqual(pr._address_to_offset(0), None)
01736         res = pr._address_to_offset(int(pr['ProcMaps'].split('-', 1)[0], 16) + 5)
01737         self.assertEqual(res.split('+', 1)[1], '5')
01738         self.assertTrue('python' in res.split('+', 1)[0])

check_ignored() for system-wise blacklist.

Definition at line 1019 of file test_report.py.

01019 
01020     def test_blacklisting(self):
01021         '''check_ignored() for system-wise blacklist.'''
01022 
01023         orig_blacklist_dir = apport.report._blacklist_dir
01024         apport.report._blacklist_dir = tempfile.mkdtemp()
01025         orig_ignore_file = apport.report._ignore_file
01026         apport.report._ignore_file = '/nonexistant'
01027         try:
01028             bash_rep = apport.report.Report()
01029             bash_rep['ExecutablePath'] = '/bin/bash'
01030             crap_rep = apport.report.Report()
01031             crap_rep['ExecutablePath'] = '/bin/crap'
01032 
01033             # no ignores initially
01034             self.assertEqual(bash_rep.check_ignored(), False)
01035             self.assertEqual(crap_rep.check_ignored(), False)
01036 
01037             # should not stumble over comments
01038             with open(os.path.join(apport.report._blacklist_dir, 'README'), 'w') as fd:
01039                 fd.write('# Ignore file\n#/bin/bash\n')
01040 
01041             # no ignores on nonmatching paths
01042             with open(os.path.join(apport.report._blacklist_dir, 'bl1'), 'w') as fd:
01043                 fd.write('/bin/bas\n/bin/bashh\nbash\nbin/bash\n')
01044             self.assertEqual(bash_rep.check_ignored(), False)
01045             self.assertEqual(crap_rep.check_ignored(), False)
01046 
01047             # ignore crap now
01048             with open(os.path.join(apport.report._blacklist_dir, 'bl_2'), 'w') as fd:
01049                 fd.write('/bin/crap\n')
01050             self.assertEqual(bash_rep.check_ignored(), False)
01051             self.assertEqual(crap_rep.check_ignored(), True)
01052 
01053             # ignore bash now
01054             with open(os.path.join(apport.report._blacklist_dir, 'bl1'), 'a') as fd:
01055                 fd.write('/bin/bash\n')
01056             self.assertEqual(bash_rep.check_ignored(), True)
01057             self.assertEqual(crap_rep.check_ignored(), True)
01058         finally:
01059             shutil.rmtree(apport.report._blacklist_dir)
01060             apport.report._blacklist_dir = orig_blacklist_dir
01061             apport.report._ignore_file = orig_ignore_file

_check_interpreted().

Definition at line 230 of file test_report.py.

00230 
00231     def test_check_interpreted(self):
00232         '''_check_interpreted().'''
00233 
00234         restore_root = False
00235         if os.getuid() == 0:
00236             # temporarily drop to normal user "mail"
00237             os.setresuid(8, 8, -1)
00238             restore_root = True
00239 
00240         try:
00241             # standard ELF binary
00242             f = tempfile.NamedTemporaryFile()
00243             pr = apport.report.Report()
00244             pr['ExecutablePath'] = '/usr/bin/gedit'
00245             pr['ProcStatus'] = 'Name:\tgedit'
00246             pr['ProcCmdline'] = 'gedit\0/' + f.name
00247             pr._check_interpreted()
00248             self.assertEqual(pr['ExecutablePath'], '/usr/bin/gedit')
00249             self.assertFalse('InterpreterPath' in pr)
00250             f.close()
00251 
00252             # bogus argv[0]
00253             pr = apport.report.Report()
00254             pr['ExecutablePath'] = '/bin/dash'
00255             pr['ProcStatus'] = 'Name:\tznonexisting'
00256             pr['ProcCmdline'] = 'nonexisting\0/foo'
00257             pr._check_interpreted()
00258             self.assertEqual(pr['ExecutablePath'], '/bin/dash')
00259             self.assertFalse('InterpreterPath' in pr)
00260 
00261             # standard sh script
00262             pr = apport.report.Report()
00263             pr['ExecutablePath'] = '/bin/dash'
00264             pr['ProcStatus'] = 'Name:\tzgrep'
00265             pr['ProcCmdline'] = '/bin/sh\0/bin/zgrep\0foo'
00266             pr._check_interpreted()
00267             self.assertEqual(pr['ExecutablePath'], '/bin/zgrep')
00268             self.assertEqual(pr['InterpreterPath'], '/bin/dash')
00269 
00270             # standard sh script when being called explicitly with interpreter
00271             pr = apport.report.Report()
00272             pr['ExecutablePath'] = '/bin/dash'
00273             pr['ProcStatus'] = 'Name:\tdash'
00274             pr['ProcCmdline'] = '/bin/sh\0/bin/zgrep\0foo'
00275             pr._check_interpreted()
00276             self.assertEqual(pr['ExecutablePath'], '/bin/zgrep')
00277             self.assertEqual(pr['InterpreterPath'], '/bin/dash')
00278 
00279             # special case mono scheme: beagled-helper (use zgrep to make the test
00280             # suite work if mono or beagle are not installed)
00281             pr = apport.report.Report()
00282             pr['ExecutablePath'] = '/usr/bin/mono'
00283             pr['ProcStatus'] = 'Name:\tzgrep'
00284             pr['ProcCmdline'] = 'zgrep\0--debug\0/bin/zgrep'
00285             pr._check_interpreted()
00286             self.assertEqual(pr['ExecutablePath'], '/bin/zgrep')
00287             self.assertEqual(pr['InterpreterPath'], '/usr/bin/mono')
00288 
00289             # special case mono scheme: banshee (use zgrep to make the test
00290             # suite work if mono or beagle are not installed)
00291             pr = apport.report.Report()
00292             pr['ExecutablePath'] = '/usr/bin/mono'
00293             pr['ProcStatus'] = 'Name:\tzgrep'
00294             pr['ProcCmdline'] = 'zgrep\0/bin/zgrep'
00295             pr._check_interpreted()
00296             self.assertEqual(pr['ExecutablePath'], '/bin/zgrep')
00297             self.assertEqual(pr['InterpreterPath'], '/usr/bin/mono')
00298 
00299             # fail on files we shouldn't have access to when name!=argv[0]
00300             pr = apport.report.Report()
00301             pr['ExecutablePath'] = '/usr/bin/python'
00302             pr['ProcStatus'] = 'Name:\tznonexisting'
00303             pr['ProcCmdline'] = 'python\0/etc/shadow'
00304             pr._check_interpreted()
00305             self.assertEqual(pr['ExecutablePath'], '/usr/bin/python')
00306             self.assertFalse('InterpreterPath' in pr)
00307 
00308             # succeed on files we should have access to when name!=argv[0]
00309             pr = apport.report.Report()
00310             pr['ExecutablePath'] = '/usr/bin/python'
00311             pr['ProcStatus'] = 'Name:\tznonexisting'
00312             pr['ProcCmdline'] = 'python\0/etc/passwd'
00313             pr._check_interpreted()
00314             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python')
00315             self.assertEqual(pr['ExecutablePath'], '/etc/passwd')
00316 
00317             # fail on files we shouldn't have access to when name==argv[0]
00318             pr = apport.report.Report()
00319             pr['ExecutablePath'] = '/usr/bin/python'
00320             pr['ProcStatus'] = 'Name:\tshadow'
00321             pr['ProcCmdline'] = '../etc/shadow'
00322             pr._check_interpreted()
00323             self.assertEqual(pr['ExecutablePath'], '/usr/bin/python')
00324             self.assertFalse('InterpreterPath' in pr)
00325 
00326             # succeed on files we should have access to when name==argv[0]
00327             pr = apport.report.Report()
00328             pr['ExecutablePath'] = '/usr/bin/python'
00329             pr['ProcStatus'] = 'Name:\tpasswd'
00330             pr['ProcCmdline'] = '../etc/passwd'
00331             pr._check_interpreted()
00332             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python')
00333             self.assertEqual(pr['ExecutablePath'], '/bin/../etc/passwd')
00334 
00335             # interactive python process
00336             pr = apport.report.Report()
00337             pr['ExecutablePath'] = '/usr/bin/python'
00338             pr['ProcStatus'] = 'Name:\tpython'
00339             pr['ProcCmdline'] = 'python'
00340             pr._check_interpreted()
00341             self.assertEqual(pr['ExecutablePath'], '/usr/bin/python')
00342             self.assertFalse('InterpreterPath' in pr)
00343 
00344             # python script (abuse /bin/bash since it must exist)
00345             pr = apport.report.Report()
00346             pr['ExecutablePath'] = '/usr/bin/python'
00347             pr['ProcStatus'] = 'Name:\tbash'
00348             pr['ProcCmdline'] = 'python\0/bin/bash'
00349             pr._check_interpreted()
00350             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python')
00351             self.assertEqual(pr['ExecutablePath'], '/bin/bash')
00352 
00353             # python script with options (abuse /bin/bash since it must exist)
00354             pr = apport.report.Report()
00355             pr['ExecutablePath'] = '/usr/bin/python'
00356             pr['ProcStatus'] = 'Name:\tbash'
00357             pr['ProcCmdline'] = 'python\0-OO\0/bin/bash'
00358             pr._check_interpreted()
00359             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python')
00360             self.assertEqual(pr['ExecutablePath'], '/bin/bash')
00361 
00362             # python script with a versioned interpreter
00363             pr = apport.report.Report()
00364             pr['ExecutablePath'] = '/usr/bin/python2.7'
00365             pr['ProcStatus'] = 'Name:\tbash'
00366             pr['ProcCmdline'] = '/usr/bin/python\0/bin/bash'
00367             pr._check_interpreted()
00368             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python2.7')
00369             self.assertEqual(pr['ExecutablePath'], '/bin/bash')
00370 
00371             # python script through -m
00372             pr = apport.report.Report()
00373             pr['ExecutablePath'] = '/usr/bin/python2.7'
00374             pr['ProcStatus'] = 'Name:\tpython'
00375             pr['ProcCmdline'] = 'python\0-tt\0-m\0apport/report\0-v'
00376             pr._check_interpreted()
00377             self.assertEqual(pr['InterpreterPath'], '/usr/bin/python2.7')
00378             self.assertTrue('report' in pr['ExecutablePath'],
00379                             'expecting "report" in ExecutablePath "%s"' % pr['ExecutablePath'])
00380         finally:
00381             if restore_root:
00382                 os.setresuid(0, 0, -1)

_check_interpreted() for programs ran through twistd

Definition at line 383 of file test_report.py.

00383 
00384     def test_check_interpreted_twistd(self):
00385         '''_check_interpreted() for programs ran through twistd'''
00386 
00387         # LP#761374
00388         pr = apport.report.Report()
00389         pr['ExecutablePath'] = '/usr/bin/python2.7'
00390         pr['ProcStatus'] = 'Name:\ttwistd'
00391         pr['ProcCmdline'] = '/usr/bin/python\0/usr/bin/twistd\0--uid\0root\0--gid\0root\0--pidfile\0/var/run/nanny.pid\0-r\0glib2\0--logfile\0/var/log/nanny.log\0-y\0/usr/share/nanny/daemon/nanny.tap'
00392         pr._check_interpreted()
00393         self.assertEqual(pr['ExecutablePath'], '/usr/share/nanny/daemon/nanny.tap')
00394         self.assertEqual(pr['InterpreterPath'], '/usr/bin/twistd')
00395 
00396         # LP#625039
00397         pr = apport.report.Report()
00398         pr['ExecutablePath'] = '/usr/bin/python2.7'
00399         pr['ProcStatus'] = 'Name:\ttwistd'
00400         pr['ProcCmdline'] = '/usr/bin/python\0/usr/bin/twistd\0--pidfile=/var/run/apt-p2p//apt-p2p.pid\0--rundir=/var/run/apt-p2p/\0--python=/usr/sbin/apt-p2p\0--logfile=/var/log/apt-p2p.log\0--no_save'
00401         pr._check_interpreted()
00402         self.assertEqual(pr['ExecutablePath'], '/usr/sbin/apt-p2p')
00403         self.assertEqual(pr['InterpreterPath'], '/usr/bin/twistd')
00404 
00405         # somewhere from LP#755025
00406         pr = apport.report.Report()
00407         pr['ExecutablePath'] = '/usr/bin/python2.7'
00408         pr['ProcStatus'] = 'Name:\ttwistd'
00409         pr['ProcCmdline'] = '/usr/bin/python\0/usr/bin/twistd\0-r\0gtk2\0--pidfile\0/tmp/vmc.pid\0-noy\0/usr/share/vodafone-mobile-connect/gtk-tap.py\0-l\0/dev/null'
00410         pr._check_interpreted()
00411         self.assertEqual(pr['ExecutablePath'], '/usr/share/vodafone-mobile-connect/gtk-tap.py')
00412         self.assertEqual(pr['InterpreterPath'], '/usr/bin/twistd')
00413 
00414         # LP#725383 -> not practical to determine file here
00415         pr = apport.report.Report()
00416         pr['ExecutablePath'] = '/usr/bin/python2.7'
00417         pr['ProcStatus'] = 'Name:\ttwistd'
00418         pr['ProcCmdline'] = '/usr/bin/python\0/usr/bin/twistd\0--pidfile=/var/run/poker-network-server.pid\0--logfile=/var/log/poker-network-server.log\0--no_save\0--reactor=poll\0pokerserver'
00419         pr._check_interpreted()
00420         self.assertTrue('ExecutablePath' in pr)
00421         self.assertTrue('UnreportableReason' in pr)
00422         self.assertEqual(pr['InterpreterPath'], '/usr/bin/twistd')

Here is the call graph for this function:

crash_signature().

Definition at line 1521 of file test_report.py.

01521 
01522     def test_crash_signature(self):
01523         '''crash_signature().'''
01524 
01525         r = apport.report.Report()
01526         self.assertEqual(r.crash_signature(), None)
01527 
01528         # signal crashes
01529         r['Signal'] = '42'
01530         r['ExecutablePath'] = '/bin/crash'
01531 
01532         r['StacktraceTop'] = '''foo_bar (x=1) at crash.c:28
01533 d01 (x=1) at crash.c:29
01534 raise () from /lib/libpthread.so.0
01535 <signal handler called>
01536 __frob::~frob (x=1) at crash.c:30'''
01537 
01538         self.assertEqual(r.crash_signature(), '/bin/crash:42:foo_bar:d01:raise:<signal handler called>:__frob::~frob')
01539 
01540         r['StacktraceTop'] = '''foo_bar (x=1) at crash.c:28
01541 ??
01542 raise () from /lib/libpthread.so.0
01543 <signal handler called>
01544 __frob (x=1) at crash.c:30'''
01545         self.assertEqual(r.crash_signature(), None)
01546 
01547         r['StacktraceTop'] = ''
01548         self.assertEqual(r.crash_signature(), None)
01549 
01550         # Python crashes
01551         del r['Signal']
01552         r['Traceback'] = '''Traceback (most recent call last):
01553   File "test.py", line 7, in <module>
01554     print(_f(5))
01555   File "test.py", line 5, in _f
01556     return g_foo00(x+1)
01557   File "test.py", line 2, in g_foo00
01558     return x/0
01559 ZeroDivisionError: integer division or modulo by zero'''
01560         self.assertEqual(r.crash_signature(), '/bin/crash:ZeroDivisionError:test.py@7:_f:g_foo00')
01561 
01562         # sometimes Python traces do not have file references
01563         r['Traceback'] = 'TypeError: function takes exactly 0 arguments (1 given)'
01564         self.assertEqual(r.crash_signature(), '/bin/crash:TypeError')
01565 
01566         r['Traceback'] = 'FooBar'
01567         self.assertEqual(r.crash_signature(), None)
01568 
01569         # kernel
01570         r['ProblemType'] = 'KernelCrash'
01571         r['Stacktrace'] = '''
01572 crash 4.0-8.9
01573 GNU gdb 6.1
01574 GDB is free software, covered by the GNU General Public License, and you are
01575 welcome to change it and/or distribute copies of it under certain conditions.
01576 Type "show copying" to see the conditions.
01577 There is absolutely no warranty for GDB.  Type "show warranty" for details.
01578 This GDB was configured as "i686-pc-linux-gnu"...
01579 
01580       KERNEL: /usr/lib/debug/boot/vmlinux-2.6.31-2-generic
01581     DUMPFILE: /tmp/tmpRJZy_O
01582         CPUS: 1
01583         DATE: Thu Jul  9 12:58:08 2009
01584       UPTIME: 00:00:57
01585 LOAD AVERAGE: 0.15, 0.05, 0.02
01586        TASKS: 173
01587     NODENAME: egon-desktop
01588      RELEASE: 2.6.31-2-generic
01589      VERSION: #16-Ubuntu SMP Mon Jul 6 20:38:51 UTC 2009
01590      MACHINE: i686  (2137 Mhz)
01591       MEMORY: 2 GB
01592        PANIC: "[   57.879776] Oops: 0002 [#1] SMP " (check log for details)
01593          PID: 0
01594      COMMAND: "swapper"
01595         TASK: c073c180  [THREAD_INFO: c0784000]
01596          CPU: 0
01597        STATE: TASK_RUNNING (PANIC)
01598 
01599 PID: 0      TASK: c073c180  CPU: 0   COMMAND: "swapper"
01600  #0 [c0785ba0] sysrq_handle_crash at c03917a3
01601     [RA: c03919c6  SP: c0785ba0  FP: c0785ba0  SIZE: 4]
01602     c0785ba0: c03919c6
01603  #1 [c0785ba0] __handle_sysrq at c03919c4
01604     [RA: c0391a91  SP: c0785ba4  FP: c0785bc8  SIZE: 40]
01605     c0785ba4: c06d4bab  c06d42d2  f6534000  00000004
01606     c0785bb4: 00000086  0000002e  00000001  f6534000
01607     c0785bc4: c0785bcc  c0391a91
01608  #2 [c0785bc8] handle_sysrq at c0391a8c
01609     [RA: c0389961  SP: c0785bcc  FP: c0785bd0  SIZE: 8]
01610     c0785bcc: c0785c0c  c0389961
01611  #3 [c0785bd0] kbd_keycode at c038995c
01612     [RA: c0389b8b  SP: c0785bd4  FP: c0785c10  SIZE: 64]
01613     c0785bd4: c056f96a  c0785be4  00000096  c07578c0
01614     c0785be4: 00000001  f6ac6e00  f6ac6e00  00000001
01615     c0785bf4: 00000000  00000000  0000002e  0000002e
01616     c0785c04: 00000001  f70d6850  c0785c1c  c0389b8b
01617  #4 [c0785c10] kbd_event at c0389b86
01618     [RA: c043140c  SP: c0785c14  FP: c0785c20  SIZE: 16]
01619     c0785c14: c0758040  f6910900  c0785c3c  c043140c
01620  #5 [c0785c20] input_pass_event at c0431409
01621     [RA: c04332ce  SP: c0785c24  FP: c0785c40  SIZE: 32]
01622     c0785c24: 00000001  0000002e  00000001  f70d6000
01623     c0785c34: 00000001  0000002e  c0785c64  c04332ce
01624  #6 [c0785c40] input_handle_event at c04332c9
01625     [RA: c0433ac6  SP: c0785c44  FP: c0785c68  SIZE: 40]
01626     c0785c44: 00000001  ffff138d  0000003d  00000001
01627     c0785c54: f70d6000  00000001  f70d6000  0000002e
01628     c0785c64: c0785c84  c0433ac6
01629  #7 [c0785c68] input_event at c0433ac1
01630     [RA: c0479806  SP: c0785c6c  FP: c0785c88  SIZE: 32]
01631     c0785c6c: 00000001  00000092  f70d677c  f70d70b4
01632     c0785c7c: 0000002e  f70d7000  c0785ca8  c0479806
01633  #8 [c0785c88] hidinput_hid_event at c0479801
01634     [RA: c0475b31  SP: c0785c8c  FP: c0785cac  SIZE: 36]
01635     c0785c8c: 00000001  00000007  c0785c00  f70d6000
01636     c0785c9c: f70d70b4  f70d5000  f70d7000  c0785cc4
01637     c0785cac: c0475b31
01638     [RA: 0  SP: c0785ffc  FP: c0785ffc  SIZE: 0]
01639    PID    PPID  CPU   TASK    ST  %MEM     VSZ    RSS  COMM
01640 >     0      0   0  c073c180  RU   0.0       0      0  [swapper]
01641       1      0   1  f7038000  IN   0.1    3096   1960  init
01642       2      0   0  f7038c90  IN   0.0       0      0  [kthreadd]
01643     271      2   1  f72bf110  IN   0.0       0      0  [bluetooth]
01644     325      2   1  f71c25b0  IN   0.0       0      0  [khungtaskd]
01645    1404      2   0  f6b5bed0  IN   0.0       0      0  [kpsmoused]
01646    1504      2   1  f649cb60  IN   0.0       0      0  [hd-audio0]
01647    2055      1   0  f6a18000  IN   0.0    1824    536  getty
01648    2056      1   0  f6a1d7f0  IN   0.0    1824    536  getty
01649    2061      1   0  f6a1f110  IN   0.1    3132   1604  login
01650    2062      1   1  f6a18c90  IN   0.0    1824    540  getty
01651    2063      1   1  f6b58c90  IN   0.0    1824    540  getty
01652    2130      1   0  f6b5f110  IN   0.0    2200   1032  acpid
01653    2169      1   0  f69ebed0  IN   0.0    2040    664  syslogd
01654    2192      1   1  f65b3ed0  IN   0.0    1976    532  dd
01655    2194      1   1  f6b5a5b0  IN   0.1    3996   2712  klogd
01656    2217      1   0  f6b74b60  IN   0.1    3008   1120  dbus-daemon
01657    2248      1   0  f65b7110  IN   0.2    6896   4304  hald
01658    2251      1   1  f65b3240  IN   0.1   19688   2604  console-kit-dae
01659 RUNQUEUES[0]: c6002320
01660  RT PRIO_ARRAY: c60023c0
01661  CFS RB_ROOT: c600237c
01662   PID: 9      TASK: f703f110  CPU: 0   COMMAND: "events/0"
01663 '''
01664         self.assertEqual(r.crash_signature(), 'kernel:sysrq_handle_crash:__handle_sysrq:handle_sysrq:kbd_keycode:kbd_event:input_pass_event:input_handle_event:input_event:hidinput_hid_event')
01665 
01666         # assertion failures
01667         r = apport.report.Report()
01668         r['Signal'] = '6'
01669         r['ExecutablePath'] = '/bin/bash'
01670         r['AssertionMessage'] = 'foo.c:42 main: i > 0'
01671         self.assertEqual(r.crash_signature(), '/bin/bash:foo.c:42 main: i > 0')

crash_signature_addresses()

Definition at line 1739 of file test_report.py.

01739 
01740     def test_crash_signature_addresses(self):
01741         '''crash_signature_addresses()'''
01742 
01743         pr = apport.report.Report()
01744         self.assertEqual(pr.crash_signature_addresses(), None)
01745 
01746         pr['ExecutablePath'] = '/bin/bash'
01747         pr['Signal'] = '42'
01748         pr['ProcMaps'] = '''
01749 00400000-004df000 r-xp 00000000 08:02 1044485                            /bin/bash
01750 006de000-006df000 r--p 000de000 08:02 1044485                            /bin/bash
01751 01596000-01597000 rw-p 00000000 00:00 0
01752 01597000-015a4000 rw-p 00000000 00:00 0                                  [heap]
01753 7f491f868000-7f491f88a000 r-xp 00000000 08:02 526219                     /lib/x86_64-linux-gnu/libtinfo.so.5.9
01754 7f491fa8f000-7f491fc24000 r-xp 00000000 08:02 522605                     /lib/x86_64-linux-gnu/libc-2.13.so
01755 7f491fc24000-7f491fe23000 ---p 00195000 08:02 522605                     /lib/with spaces !/libfoo.so
01756 7fff6e57b000-7fff6e59c000 rw-p 00000000 00:00 0                          [stack]
01757 7fff6e5ff000-7fff6e600000 r-xp 00000000 00:00 0                          [vdso]
01758 ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
01759 '''
01760 
01761         # no Stacktrace field
01762         self.assertEqual(pr.crash_signature_addresses(), None)
01763 
01764         # good stack trace
01765         pr['Stacktrace'] = '''
01766 #0  0x00007f491fac5687 in kill () at ../sysdeps/unix/syscall-template.S:82
01767 No locals.
01768 #1  0x000000000043fd51 in kill_pid ()
01769 #2  g_main_context_iterate (context=0x1731680) at gmain.c:3068
01770 #3  0x000000000042eb76 in ?? ()
01771 #4  0x00000000004324d8 in ??
01772 No symbol table info available.
01773 #5  0x00000000004707e3 in parse_and_execute ()
01774 #6  0x000000000041d703 in _start ()
01775 '''
01776         self.assertEqual(pr.crash_signature_addresses(),
01777                          '/bin/bash:42:%s:/lib/x86_64-linux-gnu/libc-2.13.so+36687:/bin/bash+3fd51:/bin/bash+2eb76:/bin/bash+324d8:/bin/bash+707e3:/bin/bash+1d703' % os.uname()[4])
01778 
01779         # all resolvable, but too short
01780         pr['Stacktrace'] = '#0  0x00007f491fac5687 in kill () at ../sysdeps/unix/syscall-template.S:82'
01781         self.assertEqual(pr.crash_signature_addresses(), None)
01782 
01783         # one unresolvable, but long enough
01784         pr['Stacktrace'] = '''
01785 #0  0x00007f491fac5687 in kill () at ../sysdeps/unix/syscall-template.S:82
01786 No locals.
01787 #1  0x000001000043fd51 in kill_pid ()
01788 #2  g_main_context_iterate (context=0x1731680) at gmain.c:3068
01789 #3  0x000000000042eb76 in ?? ()
01790 #4  0x00000000004324d8 in ??
01791 No symbol table info available.
01792 #5  0x00000000004707e3 in parse_and_execute ()
01793 #6  0x000000000041d715 in main ()
01794 #7  0x000000000041d703 in _start ()
01795 '''
01796         self.assertNotEqual(pr.crash_signature_addresses(), None)
01797 
01798         # two unresolvables, 2/7 is too much
01799         pr['Stacktrace'] = '''
01800 #0  0x00007f491fac5687 in kill () at ../sysdeps/unix/syscall-template.S:82
01801 No locals.
01802 #1  0x000001000043fd51 in kill_pid ()
01803 #2  g_main_context_iterate (context=0x1731680) at gmain.c:3068
01804 #3  0x000001000042eb76 in ?? ()
01805 #4  0x00000000004324d8 in ??
01806 No symbol table info available.
01807 #5  0x00000000004707e3 in parse_and_execute ()
01808 #6  0x000000000041d715 in main ()
01809 #7  0x000000000041d703 in _start ()
01810 '''
01811         self.assertEqual(pr.crash_signature_addresses(), None)

_gen_stacktrace_top().

Definition at line 1325 of file test_report.py.

01325 
01326     def test_gen_stacktrace_top(self):
01327         '''_gen_stacktrace_top().'''
01328 
01329         # nothing to chop off
01330         r = apport.report.Report()
01331         r['Stacktrace'] = '''#0  0x10000488 in h (p=0x0) at crash.c:25
01332 #1  0x100004c8 in g (x=1, y=42) at crash.c:26
01333 #2  0x10000514 in f (x=1) at crash.c:27
01334 #3  0x10000530 in e (x=1) at crash.c:28
01335 #4  0x10000530 in d (x=1) at crash.c:29
01336 #5  0x10000530 in c (x=1) at crash.c:30
01337 #6  0x10000550 in main () at crash.c:31
01338 '''
01339         r._gen_stacktrace_top()
01340         self.assertEqual(r['StacktraceTop'], '''h (p=0x0) at crash.c:25
01341 g (x=1, y=42) at crash.c:26
01342 f (x=1) at crash.c:27
01343 e (x=1) at crash.c:28
01344 d (x=1) at crash.c:29''')
01345 
01346         # nothing to chop off: some addresses missing (LP #269133)
01347         r = apport.report.Report()
01348         r['Stacktrace'] = '''#0 h (p=0x0) at crash.c:25
01349 #1  0x100004c8 in g (x=1, y=42) at crash.c:26
01350 #2 f (x=1) at crash.c:27
01351 #3  0x10000530 in e (x=1) at crash.c:28
01352 #4  0x10000530 in d (x=1) at crash.c:29
01353 #5  0x10000530 in c (x=1) at crash.c:30
01354 #6  0x10000550 in main () at crash.c:31
01355 '''
01356         r._gen_stacktrace_top()
01357         self.assertEqual(r['StacktraceTop'], '''h (p=0x0) at crash.c:25
01358 g (x=1, y=42) at crash.c:26
01359 f (x=1) at crash.c:27
01360 e (x=1) at crash.c:28
01361 d (x=1) at crash.c:29''')
01362 
01363         # single signal handler invocation
01364         r = apport.report.Report()
01365         r['Stacktrace'] = '''#0  0x10000488 in raise () from /lib/libpthread.so.0
01366 #1  0x100004c8 in ??
01367 #2  <signal handler called>
01368 #3  0x10000530 in e (x=1) at crash.c:28
01369 #4  0x10000530 in d (x=1) at crash.c:29
01370 #5  0x10000530 in c (x=1) at crash.c:30
01371 #6  0x10000550 in main () at crash.c:31
01372 '''
01373         r._gen_stacktrace_top()
01374         self.assertEqual(r['StacktraceTop'], '''e (x=1) at crash.c:28
01375 d (x=1) at crash.c:29
01376 c (x=1) at crash.c:30
01377 main () at crash.c:31''')
01378 
01379         # single signal handler invocation: some addresses missing
01380         r = apport.report.Report()
01381         r['Stacktrace'] = '''#0  0x10000488 in raise () from /lib/libpthread.so.0
01382 #1  ??
01383 #2  <signal handler called>
01384 #3  0x10000530 in e (x=1) at crash.c:28
01385 #4  d (x=1) at crash.c:29
01386 #5  0x10000530 in c (x=1) at crash.c:30
01387 #6  0x10000550 in main () at crash.c:31
01388 '''
01389         r._gen_stacktrace_top()
01390         self.assertEqual(r['StacktraceTop'], '''e (x=1) at crash.c:28
01391 d (x=1) at crash.c:29
01392 c (x=1) at crash.c:30
01393 main () at crash.c:31''')
01394 
01395         # stacked signal handler; should only cut the first one
01396         r = apport.report.Report()
01397         r['Stacktrace'] = '''#0  0x10000488 in raise () from /lib/libpthread.so.0
01398 #1  0x100004c8 in ??
01399 #2  <signal handler called>
01400 #3  0x10000530 in e (x=1) at crash.c:28
01401 #4  0x10000530 in d (x=1) at crash.c:29
01402 #5  0x10000123 in raise () from /lib/libpthread.so.0
01403 #6  <signal handler called>
01404 #7  0x10000530 in c (x=1) at crash.c:30
01405 #8  0x10000550 in main () at crash.c:31
01406 '''
01407         r._gen_stacktrace_top()
01408         self.assertEqual(r['StacktraceTop'], '''e (x=1) at crash.c:28
01409 d (x=1) at crash.c:29
01410 raise () from /lib/libpthread.so.0
01411 <signal handler called>
01412 c (x=1) at crash.c:30''')
01413 
01414         # Gnome assertion; should unwind the logs and assert call
01415         r = apport.report.Report()
01416         r['Stacktrace'] = '''#0  0xb7d39cab in IA__g_logv (log_domain=<value optimized out>, log_level=G_LOG_LEVEL_ERROR,
01417     format=0xb7d825f0 "file %s: line %d (%s): assertion failed: (%s)", args1=0xbfee8e3c "xxx") at /build/buildd/glib2.0-2.13.5/glib/gmessages.c:493
01418 #1  0xb7d39f29 in IA__g_log (log_domain=0xb7edbfd0 "libgnomevfs", log_level=G_LOG_LEVEL_ERROR,
01419     format=0xb7d825f0 "file %s: line %d (%s): assertion failed: (%s)") at /build/buildd/glib2.0-2.13.5/glib/gmessages.c:517
01420 #2  0xb7d39fa6 in IA__g_assert_warning (log_domain=0xb7edbfd0 "libgnomevfs", file=0xb7ee1a26 "gnome-vfs-volume.c", line=254,
01421     pretty_function=0xb7ee1920 "gnome_vfs_volume_unset_drive_private", expression=0xb7ee1a39 "volume->priv->drive == drive")
01422     at /build/buildd/glib2.0-2.13.5/glib/gmessages.c:552
01423 No locals.
01424 #3  0xb7ec6c11 in gnome_vfs_volume_unset_drive_private (volume=0x8081a30, drive=0x8078f00) at gnome-vfs-volume.c:254
01425         __PRETTY_FUNCTION__ = "gnome_vfs_volume_unset_drive_private"
01426 #4  0x08054db8 in _gnome_vfs_volume_monitor_disconnected (volume_monitor=0x8070400, drive=0x8078f00) at gnome-vfs-volume-monitor.c:963
01427         vol_list = (GList *) 0x8096d30
01428         current_vol = (GList *) 0x8097470
01429 #5  0x0805951e in _hal_device_removed (hal_ctx=0x8074da8, udi=0x8093be4 "/org/freedesktop/Hal/devices/volume_uuid_92FC9DFBFC9DDA35")
01430     at gnome-vfs-hal-mounts.c:1316
01431         backing_udi = <value optimized out>
01432 #6  0xb7ef1ead in filter_func (connection=0x8075288, message=0x80768d8, user_data=0x8074da8) at libhal.c:820
01433         udi = <value optimized out>
01434         object_path = 0x8076d40 "/org/freedesktop/Hal/Manager"
01435         error = {name = 0x0, message = 0x0, dummy1 = 1, dummy2 = 0, dummy3 = 0, dummy4 = 1, dummy5 = 0, padding1 = 0xb7e50c00}
01436 #7  0xb7e071d2 in dbus_connection_dispatch (connection=0x8075288) at dbus-connection.c:4267
01437 #8  0xb7e33dfd in ?? () from /usr/lib/libdbus-glib-1.so.2'''
01438         r._gen_stacktrace_top()
01439         self.assertEqual(r['StacktraceTop'], '''gnome_vfs_volume_unset_drive_private (volume=0x8081a30, drive=0x8078f00) at gnome-vfs-volume.c:254
01440 _gnome_vfs_volume_monitor_disconnected (volume_monitor=0x8070400, drive=0x8078f00) at gnome-vfs-volume-monitor.c:963
01441 _hal_device_removed (hal_ctx=0x8074da8, udi=0x8093be4 "/org/freedesktop/Hal/devices/volume_uuid_92FC9DFBFC9DDA35")
01442 filter_func (connection=0x8075288, message=0x80768d8, user_data=0x8074da8) at libhal.c:820
01443 dbus_connection_dispatch (connection=0x8075288) at dbus-connection.c:4267''')
01444 
01445         # XError (taken from LP#848808)
01446         r = apport.report.Report()
01447         r['Stacktrace'] = '''#0  0x007cf416 in __kernel_vsyscall ()
01448 No symbol table info available.
01449 #1  0x01017c8f in __GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
01450 #2  0x0101b2b5 in __GI_abort () at abort.c:92
01451 #3  0x0807daab in meta_bug (format=0x80b0c60 "Unexpected X error: %s serial %ld error_code %d request_code %d minor_code %d)\n") at core/util.c:398
01452 #4  0x0806989c in x_error_handler (error=0xbf924acc, xdisplay=0x9104b88) at core/errors.c:247
01453 #5  x_error_handler (xdisplay=0x9104b88, error=0xbf924acc) at core/errors.c:203
01454 #6  0x00e97d3b in _XError (dpy=0x9104b88, rep=0x9131840) at ../../src/XlibInt.c:1583
01455 #7  0x00e9490d in handle_error (dpy=0x9104b88, err=0x9131840, in_XReply=0) at ../../src/xcb_io.c:212
01456 #8  0x00e94967 in handle_response (dpy=0x9104b88, response=0x9131840, in_XReply=0) at ../../src/xcb_io.c:324
01457 #9  0x00e952fe in _XReadEvents (dpy=0x9104b88) at ../../src/xcb_io.c:425
01458 #10 0x00e93663 in XWindowEvent (dpy=0x9104b88, w=16777220, mask=4194304, event=0xbf924c6c) at ../../src/WinEvent.c:79
01459 #11 0x0806071c in meta_display_get_current_time_roundtrip (display=0x916d7d0) at core/display.c:1217
01460 #12 0x08089f64 in meta_window_show (window=0x91ccfc8) at core/window.c:2165
01461 #13 implement_showing (window=0x91ccfc8, showing=1) at core/window.c:1583
01462 #14 0x080879cc in meta_window_flush_calc_showing (window=0x91ccfc8) at core/window.c:1806'''
01463         r._gen_stacktrace_top()
01464         self.assertEqual(r['StacktraceTop'], '''meta_display_get_current_time_roundtrip (display=0x916d7d0) at core/display.c:1217
01465 meta_window_show (window=0x91ccfc8) at core/window.c:2165
01466 implement_showing (window=0x91ccfc8, showing=1) at core/window.c:1583
01467 meta_window_flush_calc_showing (window=0x91ccfc8) at core/window.c:1806''')
01468 
01469         # another XError (taken from LP#834403)
01470         r = apport.report.Report()
01471         r['Stacktrace'] = '''#0  g_logv (log_domain=0x7fd41db08a46 "Gdk", log_level=<optimized out>, format=0x7fd41db12e87 "%s", args1=0x7fff50bf0c18) at /build/buildd/glib2.0-2.29.16/./glib/gmessages.c:577
01472 #1  0x00007fd42006bb92 in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at /build/buildd/glib2.0-2.29.16/./glib/gmessages.c:591
01473 #2  0x00007fd41dae86f3 in _gdk_x11_display_error_event (display=<optimized out>, error=<optimized out>) at /build/buildd/gtk+3.0-3.1.12/./gdk/x11/gdkdisplay-x11.c:2374
01474 #3  0x00007fd41daf5647 in gdk_x_error (error=0x7fff50bf0dc0, xdisplay=<optimized out>) at /build/buildd/gtk+3.0-3.1.12/./gdk/x11/gdkmain-x11.c:312
01475 #4  gdk_x_error (xdisplay=<optimized out>, error=0x7fff50bf0dc0) at /build/buildd/gtk+3.0-3.1.12/./gdk/x11/gdkmain-x11.c:275
01476 #5  0x00007fd41d5a301f in _XError (dpy=0x2425370, rep=<optimized out>) at ../../src/XlibInt.c:1583
01477 #6  0x00007fd41d59fdd1 in handle_error (dpy=0x2425370, err=0x7fd408707980, in_XReply=<optimized out>) at ../../src/xcb_io.c:212
01478 #7  0x00007fd41d5a0d27 in _XReply (dpy=0x2425370, rep=0x7fff50bf0f60, extra=0, discard=0) at ../../src/xcb_io.c:698
01479 #8  0x00007fd41d5852fb in XGetWindowProperty (dpy=0x2425370, w=0, property=348, offset=0, length=2, delete=<optimized out>, req_type=348, actual_type=0x7fff50bf1038, actual_format=0x7fff50bf105c, nitems=0x7fff50bf1040, bytesafter=0x7fff50bf1048, prop=0x7fff50bf1050) at ../../src/GetProp.c:61
01480 #9  0x00007fd41938269e in window_is_xembed (w=<optimized out>, d=<optimized out>) at canberra-gtk-module.c:373
01481 #10 dispatch_sound_event (d=0x32f6a30) at canberra-gtk-module.c:454
01482 #11 dispatch_queue () at canberra-gtk-module.c:815'''
01483         r._gen_stacktrace_top()
01484         self.assertEqual(r['StacktraceTop'], '''XGetWindowProperty (dpy=0x2425370, w=0, property=348, offset=0, length=2, delete=<optimized out>, req_type=348, actual_type=0x7fff50bf1038, actual_format=0x7fff50bf105c, nitems=0x7fff50bf1040, bytesafter=0x7fff50bf1048, prop=0x7fff50bf1050) at ../../src/GetProp.c:61
01485 window_is_xembed (w=<optimized out>, d=<optimized out>) at canberra-gtk-module.c:373
01486 dispatch_sound_event (d=0x32f6a30) at canberra-gtk-module.c:454
01487 dispatch_queue () at canberra-gtk-module.c:815''')
01488 
01489         # problem with too old gdb, only assertion, nothing else
01490         r = apport.report.Report()
01491         r['Stacktrace'] = '''#0  0x00987416 in __kernel_vsyscall ()
01492 No symbol table info available.
01493 #1  0x00ebecb1 in *__GI_raise (sig=6)
01494         selftid = 945
01495 #2  0x00ec218e in *__GI_abort () at abort.c:59
01496         save_stage = Unhandled dwarf expression opcode 0x9f
01497 '''
01498         r._gen_stacktrace_top()
01499         self.assertEqual(r['StacktraceTop'], '')
01500 
01501         # ignore uninteresting frames
01502         r = apport.report.Report()
01503         r['Stacktrace'] = '''#0  0x00987416 in __kernel_vsyscall ()
01504 #1  __strchr_sse42 () at strchr.S:97
01505 #2 h (p=0x0) at crash.c:25
01506 #3  0x100004c8 in g (x=1, y=42) at crash.c:26
01507 #4  0x10000999 in __memmove_ssse3 ()
01508 #5 f (x=1) at crash.c:27
01509 #6  0x10000530 in e (x=1) at crash.c:28
01510 #7  0x10000999 in __strlen_sse2_back () at strchr.S:42
01511 #8  0x10000530 in d (x=1) at crash.c:29
01512 #9  0x10000530 in c (x=1) at crash.c:30
01513 #10 0x10000550 in main () at crash.c:31
01514 '''
01515         r._gen_stacktrace_top()
01516         self.assertEqual(r['StacktraceTop'], '''h (p=0x0) at crash.c:25
01517 g (x=1, y=42) at crash.c:26
01518 f (x=1) at crash.c:27
01519 e (x=1) at crash.c:28
01520 d (x=1) at crash.c:29''')

has_useful_stacktrace().

Definition at line 1105 of file test_report.py.

01105 
01106     def test_has_useful_stacktrace(self):
01107         '''has_useful_stacktrace().'''
01108 
01109         r = apport.report.Report()
01110         self.assertFalse(r.has_useful_stacktrace())
01111 
01112         r['StacktraceTop'] = ''
01113         self.assertFalse(r.has_useful_stacktrace())
01114 
01115         r['StacktraceTop'] = '?? ()'
01116         self.assertFalse(r.has_useful_stacktrace())
01117 
01118         r['StacktraceTop'] = '?? ()\n?? ()'
01119         self.assertFalse(r.has_useful_stacktrace())
01120 
01121         r['StacktraceTop'] = 'read () from /lib/libc.6.so\n?? ()'
01122         self.assertFalse(r.has_useful_stacktrace())
01123 
01124         r['StacktraceTop'] = 'read () from /lib/libc.6.so\n?? ()\n?? ()\n?? ()'
01125         self.assertFalse(r.has_useful_stacktrace())
01126 
01127         r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so'
01128         self.assertTrue(r.has_useful_stacktrace())
01129 
01130         r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()'
01131         self.assertTrue(r.has_useful_stacktrace())
01132 
01133         r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()\n?? ()'
01134         self.assertTrue(r.has_useful_stacktrace())
01135 
01136         r['StacktraceTop'] = 'read () from /lib/libc.6.so\n?? ()\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()\n?? ()'
01137         self.assertFalse(r.has_useful_stacktrace())

mark_ignore() and check_ignored().

Definition at line 959 of file test_report.py.

00959 
00960     def test_ignoring(self):
00961         '''mark_ignore() and check_ignored().'''
00962 
00963         orig_ignore_file = apport.report.apport.report._ignore_file
00964         workdir = tempfile.mkdtemp()
00965         apport.report.apport.report._ignore_file = os.path.join(workdir, 'ignore.xml')
00966         try:
00967             with open(os.path.join(workdir, 'bash'), 'w') as fd:
00968                 fd.write('bash')
00969             with open(os.path.join(workdir, 'crap'), 'w') as fd:
00970                 fd.write('crap')
00971 
00972             bash_rep = apport.report.Report()
00973             bash_rep['ExecutablePath'] = os.path.join(workdir, 'bash')
00974             crap_rep = apport.report.Report()
00975             crap_rep['ExecutablePath'] = os.path.join(workdir, 'crap')
00976             # must be able to deal with executables that do not exist any more
00977             cp_rep = apport.report.Report()
00978             cp_rep['ExecutablePath'] = os.path.join(workdir, 'cp')
00979 
00980             # no ignores initially
00981             self.assertEqual(bash_rep.check_ignored(), False)
00982             self.assertEqual(crap_rep.check_ignored(), False)
00983             self.assertEqual(cp_rep.check_ignored(), False)
00984 
00985             # ignore crap now
00986             crap_rep.mark_ignore()
00987             self.assertEqual(bash_rep.check_ignored(), False)
00988             self.assertEqual(crap_rep.check_ignored(), True)
00989             self.assertEqual(cp_rep.check_ignored(), False)
00990 
00991             # ignore bash now
00992             bash_rep.mark_ignore()
00993             self.assertEqual(bash_rep.check_ignored(), True)
00994             self.assertEqual(crap_rep.check_ignored(), True)
00995             self.assertEqual(cp_rep.check_ignored(), False)
00996 
00997             # poke crap so that it has a newer timestamp
00998             time.sleep(1)
00999             with open(os.path.join(workdir, 'crap'), 'w') as fd:
01000                 fd.write('crapnew')
01001             self.assertEqual(bash_rep.check_ignored(), True)
01002             self.assertEqual(crap_rep.check_ignored(), False)
01003             self.assertEqual(cp_rep.check_ignored(), False)
01004 
01005             # do not complain about an empty ignore file
01006             with open(apport.report.apport.report._ignore_file, 'w') as fd:
01007                 fd.write('')
01008             self.assertEqual(bash_rep.check_ignored(), False)
01009             self.assertEqual(crap_rep.check_ignored(), False)
01010             self.assertEqual(cp_rep.check_ignored(), False)
01011 
01012             # does not crash if the executable went away under our feet
01013             crap_rep['ExecutablePath'] = '/non existing'
01014             crap_rep.mark_ignore()
01015             self.assertEqual(os.path.getsize(apport.report.apport.report._ignore_file), 0)
01016         finally:
01017             shutil.rmtree(workdir)
01018             apport.report.apport.report._ignore_file = orig_ignore_file

methods get along with non-ASCII data

Definition at line 1672 of file test_report.py.

01672 
01673     def test_nonascii_data(self):
01674         '''methods get along with non-ASCII data'''
01675 
01676         # fake os.uname() into reporting a non-ASCII name
01677         uname = os.uname()
01678         uname = (uname[0], b't\xe2\x99\xaax'.decode('UTF-8'), uname[2], uname[3], uname[4])
01679         orig_uname = os.uname
01680         os.uname = lambda: uname
01681 
01682         try:
01683             pr = apport.report.Report()
01684             utf8_val = b'\xc3\xa4 ' + uname[1].encode('UTF-8') + b' \xe2\x99\xa5 '
01685             pr['ProcUnicodeValue'] = utf8_val.decode('UTF-8')
01686             pr['ProcByteArrayValue'] = utf8_val
01687 
01688             pr.anonymize()
01689 
01690             exp_utf8 = b'\xc3\xa4 hostname \xe2\x99\xa5 '
01691             self.assertEqual(pr['ProcUnicodeValue'], exp_utf8.decode('UTF-8'))
01692             self.assertEqual(pr['ProcByteArrayValue'], exp_utf8)
01693         finally:
01694             os.uname = orig_uname

obsolete_packages().

Definition at line 1299 of file test_report.py.

01299 
01300     def test_obsolete_packages(self):
01301         '''obsolete_packages().'''
01302 
01303         report = apport.report.Report()
01304         self.assertEqual(report.obsolete_packages(), [])
01305 
01306         # should work without Dependencies
01307         report['Package'] = 'bash 0'
01308         self.assertEqual(report.obsolete_packages(), ['bash'])
01309         report['Package'] = 'bash 0 [modified: /bin/bash]'
01310         self.assertEqual(report.obsolete_packages(), ['bash'])
01311         report['Package'] = 'bash ' + apport.packaging.get_available_version('bash')
01312         self.assertEqual(report.obsolete_packages(), [])
01313 
01314         report['Dependencies'] = 'coreutils 0\ncron 0\n'
01315         self.assertEqual(report.obsolete_packages(), ['coreutils', 'cron'])
01316 
01317         report['Dependencies'] = 'coreutils %s [modified: /bin/mount]\ncron 0\n' % \
01318             apport.packaging.get_available_version('coreutils')
01319         self.assertEqual(report.obsolete_packages(), ['cron'])
01320 
01321         report['Dependencies'] = 'coreutils %s\ncron %s\n' % (
01322             apport.packaging.get_available_version('coreutils'),
01323             apport.packaging.get_available_version('cron'))
01324         self.assertEqual(report.obsolete_packages(), [])

search_bug_patterns().

Definition at line 718 of file test_report.py.

00718 
00719     def test_search_bug_patterns(self):
00720         '''search_bug_patterns().'''
00721 
00722         patterns = tempfile.NamedTemporaryFile(prefix='apport-')
00723         # create some test patterns
00724         patterns.write(b'''<?xml version="1.0"?>
00725 <patterns>
00726     <pattern url="http://bugtracker.net/bugs/1">
00727         <re key="Package">^bash </re>
00728         <re key="Foo">ba.*r</re>
00729     </pattern>
00730     <pattern url="http://bugtracker.net/bugs/2">
00731         <re key="Package">^bash 1-2$</re>
00732         <re key="Foo">write_(hello|goodbye)</re>
00733     </pattern>
00734     <pattern url="http://bugtracker.net/bugs/3">
00735         <re key="Package">^coreutils </re>
00736         <re key="Bar">^1$</re>
00737     </pattern>
00738     <pattern url="http://bugtracker.net/bugs/4">
00739         <re key="Package">^coreutils </re>
00740         <re></re>
00741         <re key="Bar">*</re> <!-- invalid RE -->
00742         <re key="broken">+[1^</re>
00743     </pattern>
00744     <pattern url="http://bugtracker.net/bugs/5">
00745         <re key="SourcePackage">^bazaar$</re>
00746         <re key="LogFile">AssertionError</re>
00747     </pattern>
00748 </patterns>''')
00749         patterns.flush()
00750 
00751         # invalid XML
00752         invalid = tempfile.NamedTemporaryFile(prefix='apport-')
00753         invalid.write(b'''<?xml version="1.0"?>
00754 </patterns>''')
00755         invalid.flush()
00756 
00757         # create some reports
00758         r_bash = apport.report.Report()
00759         r_bash['Package'] = 'bash 1-2'
00760         r_bash['Foo'] = 'bazaar'
00761 
00762         r_bazaar = apport.report.Report()
00763         r_bazaar['Package'] = 'bazaar 2-1'
00764         r_bazaar['SourcePackage'] = 'bazaar'
00765         r_bazaar['LogFile'] = 'AssertionError'
00766 
00767         r_coreutils = apport.report.Report()
00768         r_coreutils['Package'] = 'coreutils 1'
00769         r_coreutils['Bar'] = '1'
00770 
00771         r_invalid = apport.report.Report()
00772         r_invalid['Package'] = 'invalid 1'
00773 
00774         pattern_url = 'file://' + patterns.name
00775 
00776         # positive match cases
00777         self.assertEqual(r_bash.search_bug_patterns(pattern_url),
00778                          'http://bugtracker.net/bugs/1')
00779         r_bash['Foo'] = 'write_goodbye'
00780         self.assertEqual(r_bash.search_bug_patterns(pattern_url),
00781                          'http://bugtracker.net/bugs/2')
00782         self.assertEqual(r_coreutils.search_bug_patterns(pattern_url),
00783                          'http://bugtracker.net/bugs/3')
00784         self.assertEqual(r_bazaar.search_bug_patterns(pattern_url),
00785                          'http://bugtracker.net/bugs/5')
00786 
00787         # also works for CompressedValues
00788         r_bash_compressed = r_bash.copy()
00789         r_bash_compressed['Foo'] = problem_report.CompressedValue(b'bazaar')
00790         self.assertEqual(r_bash_compressed.search_bug_patterns(pattern_url),
00791                          'http://bugtracker.net/bugs/1')
00792 
00793         # negative match cases
00794         r_bash['Package'] = 'bash-static 1-2'
00795         self.assertEqual(r_bash.search_bug_patterns(pattern_url), None)
00796         r_bash['Package'] = 'bash 1-21'
00797         self.assertEqual(r_bash.search_bug_patterns(pattern_url), None,
00798                          'does not match on wrong bash version')
00799         r_bash['Foo'] = 'zz'
00800         self.assertEqual(r_bash.search_bug_patterns(pattern_url), None,
00801                          'does not match on wrong Foo value')
00802         r_coreutils['Bar'] = '11'
00803         self.assertEqual(r_coreutils.search_bug_patterns(pattern_url), None,
00804                          'does not match on wrong Bar value')
00805         r_bazaar['SourcePackage'] = 'launchpad'
00806         self.assertEqual(r_bazaar.search_bug_patterns(pattern_url), None,
00807                          'does not match on wrong source package')
00808         r_bazaar['LogFile'] = ''
00809         self.assertEqual(r_bazaar.search_bug_patterns(pattern_url), None,
00810                          'does not match on empty attribute')
00811 
00812         # various errors to check for robustness (no exceptions, just None
00813         # return value)
00814         del r_coreutils['Bar']
00815         self.assertEqual(r_coreutils.search_bug_patterns(pattern_url), None,
00816                          'does not match on nonexisting key')
00817         self.assertEqual(r_invalid.search_bug_patterns('file://' + invalid.name), None,
00818                          'gracefully handles invalid XML')
00819         r_coreutils['Package'] = 'other 2'
00820         self.assertEqual(r_bash.search_bug_patterns('file:///nonexisting/directory/'), None,
00821                          'gracefully handles nonexisting base path')
00822         # existing host, but no bug patterns
00823         self.assertEqual(r_bash.search_bug_patterns('http://security.ubuntu.com/'), None,
00824                          'gracefully handles base path without bug patterns')
00825         # nonexisting host
00826         self.assertEqual(r_bash.search_bug_patterns('http://nonexisting.domain/'), None,
00827                          'gracefully handles nonexisting URL domain')

standard_title().

Definition at line 1138 of file test_report.py.

01138 
01139     def test_standard_title(self):
01140         '''standard_title().'''
01141 
01142         report = apport.report.Report()
01143         self.assertEqual(report.standard_title(), None)
01144 
01145         # named signal crash
01146         report['Signal'] = '11'
01147         report['ExecutablePath'] = '/bin/bash'
01148         report['StacktraceTop'] = '''foo()
01149 bar(x=3)
01150 baz()
01151 '''
01152         self.assertEqual(report.standard_title(),
01153                          'bash crashed with SIGSEGV in foo()')
01154 
01155         # unnamed signal crash
01156         report['Signal'] = '42'
01157         self.assertEqual(report.standard_title(),
01158                          'bash crashed with signal 42 in foo()')
01159 
01160         # do not crash on empty StacktraceTop
01161         report['StacktraceTop'] = ''
01162         self.assertEqual(report.standard_title(),
01163                          'bash crashed with signal 42')
01164 
01165         # do not create bug title with unknown function name
01166         report['StacktraceTop'] = '??()\nfoo()'
01167         self.assertEqual(report.standard_title(),
01168                          'bash crashed with signal 42 in foo()')
01169 
01170         # if we do not know any function name, don't mention ??
01171         report['StacktraceTop'] = '??()\n??()'
01172         self.assertEqual(report.standard_title(),
01173                          'bash crashed with signal 42')
01174 
01175         # assertion message
01176         report['Signal'] = '6'
01177         report['ExecutablePath'] = '/bin/bash'
01178         report['AssertionMessage'] = 'foo.c:42 main: i > 0'
01179         self.assertEqual(report.standard_title(),
01180                          'bash assert failure: foo.c:42 main: i > 0')
01181 
01182         # Python crash
01183         report = apport.report.Report()
01184         report['ExecutablePath'] = '/usr/share/apport/apport-gtk'
01185         report['Traceback'] = '''Traceback (most recent call last):
01186 File "/usr/share/apport/apport-gtk", line 202, in <module>
01187 app.run_argv()
01188 File "/var/lib/python-support/python2.5/apport/ui.py", line 161, in run_argv
01189 self.run_crashes()
01190 File "/var/lib/python-support/python2.5/apport/ui.py", line 104, in run_crashes
01191 self.run_crash(f)
01192 File "/var/lib/python-support/python2.5/apport/ui.py", line 115, in run_crash
01193 response = self.ui_present_crash(desktop_entry)
01194 File "/usr/share/apport/apport-gtk", line 67, in ui_present_crash
01195 subprocess.call(['pgrep', '-x',
01196 NameError: global name 'subprocess' is not defined'''
01197         self.assertEqual(report.standard_title(),
01198                          "apport-gtk crashed with NameError in ui_present_crash(): global name 'subprocess' is not defined")
01199 
01200         # slightly weird Python crash
01201         report = apport.report.Report()
01202         report['ExecutablePath'] = '/usr/share/apport/apport-gtk'
01203         report['Traceback'] = '''TypeError: Cannot create a consistent method resolution
01204 order (MRO) for bases GObject, CanvasGroupableIface, CanvasGroupable'''
01205         self.assertEqual(report.standard_title(),
01206                          'apport-gtk crashed with TypeError: Cannot create a consistent method resolution')
01207 
01208         # Python crash with custom message
01209         report = apport.report.Report()
01210         report['ExecutablePath'] = '/usr/share/apport/apport-gtk'
01211         report['Traceback'] = '''Traceback (most recent call last):
01212   File "/x/foo.py", line 242, in setup_chooser
01213     raise "Moo"
01214 Mo?o[a-1]'''
01215 
01216         self.assertEqual(report.standard_title(), 'apport-gtk crashed with Mo?o[a-1] in setup_chooser()')
01217 
01218         # Python crash with custom message with newlines (LP #190947)
01219         report = apport.report.Report()
01220         report['ExecutablePath'] = '/usr/share/apport/apport-gtk'
01221         report['Traceback'] = '''Traceback (most recent call last):
01222   File "/x/foo.py", line 242, in setup_chooser
01223     raise "\nKey: "+key+" isn't set.\nRestarting AWN usually solves this issue\n"
01224 
01225 Key: /apps/avant-window-navigator/app/active_png isn't set.
01226 Restarting AWN usually solves this issue'''
01227 
01228         t = report.standard_title()
01229         self.assertTrue(t.startswith('apport-gtk crashed with'))
01230         self.assertTrue(t.endswith('setup_chooser()'))
01231 
01232         # Python crash at top level in module
01233         report = apport.report.Report()
01234         report['ExecutablePath'] = '/usr/bin/gnome-about'
01235         report['Traceback'] = '''Traceback (most recent call last):
01236   File "/usr/bin/gnome-about", line 30, in <module>
01237     import pygtk
01238   File "/usr/lib/pymodules/python2.6/pygtk.py", line 28, in <module>
01239     import nonexistent
01240 ImportError: No module named nonexistent
01241 '''
01242         self.assertEqual(report.standard_title(),
01243                          "gnome-about crashed with ImportError in /usr/lib/pymodules/python2.6/pygtk.py: No module named nonexistent")
01244 
01245         # Python crash at top level in main program
01246         report = apport.report.Report()
01247         report['ExecutablePath'] = '/usr/bin/dcut'
01248         report['Traceback'] = '''Traceback (most recent call last):
01249   File "/usr/bin/dcut", line 28, in <module>
01250     import nonexistent
01251 ImportError: No module named nonexistent
01252 '''
01253         self.assertEqual(report.standard_title(),
01254                          "dcut crashed with ImportError in __main__: No module named nonexistent")
01255 
01256         # package install problem
01257         report = apport.report.Report('Package')
01258         report['Package'] = 'bash'
01259 
01260         # no ErrorMessage
01261         self.assertEqual(report.standard_title(),
01262                          'package bash failed to install/upgrade')
01263 
01264         # empty ErrorMessage
01265         report['ErrorMessage'] = ''
01266         self.assertEqual(report.standard_title(),
01267                          'package bash failed to install/upgrade')
01268 
01269         # nonempty ErrorMessage
01270         report['ErrorMessage'] = 'botched\nnot found\n'
01271         self.assertEqual(report.standard_title(),
01272                          'package bash failed to install/upgrade: not found')
01273 
01274         # matching package/system architectures
01275         report['Signal'] = '11'
01276         report['ExecutablePath'] = '/bin/bash'
01277         report['StacktraceTop'] = '''foo()
01278 bar(x=3)
01279 baz()
01280 '''
01281         report['PackageArchitecture'] = 'amd64'
01282         report['Architecture'] = 'amd64'
01283         self.assertEqual(report.standard_title(),
01284                          'bash crashed with SIGSEGV in foo()')
01285 
01286         # non-native package (on multiarch)
01287         report['PackageArchitecture'] = 'i386'
01288         self.assertEqual(report.standard_title(),
01289                          'bash crashed with SIGSEGV in foo() [non-native i386 package]')
01290 
01291         # Arch: all package (matches every system architecture)
01292         report['PackageArchitecture'] = 'all'
01293         self.assertEqual(report.standard_title(),
01294                          'bash crashed with SIGSEGV in foo()')
01295 
01296         report = apport.report.Report('KernelOops')
01297         report['OopsText'] = '------------[ cut here ]------------\nkernel BUG at /tmp/oops.c:5!\ninvalid opcode: 0000 [#1] SMP'
01298         self.assertEqual(report.standard_title(), 'kernel BUG at /tmp/oops.c:5!')

Here is the call graph for this function:

check_ignored() for system-wise whitelist.

Definition at line 1062 of file test_report.py.

01062 
01063     def test_whitelisting(self):
01064         '''check_ignored() for system-wise whitelist.'''
01065 
01066         orig_whitelist_dir = apport.report._whitelist_dir
01067         apport.report._whitelist_dir = tempfile.mkdtemp()
01068         orig_ignore_file = apport.report.apport.report._ignore_file
01069         apport.report.apport.report._ignore_file = '/nonexistant'
01070         try:
01071             bash_rep = apport.report.Report()
01072             bash_rep['ExecutablePath'] = '/bin/bash'
01073             crap_rep = apport.report.Report()
01074             crap_rep['ExecutablePath'] = '/bin/crap'
01075 
01076             # no ignores without any whitelist
01077             self.assertEqual(bash_rep.check_ignored(), False)
01078             self.assertEqual(crap_rep.check_ignored(), False)
01079 
01080             # should not stumble over comments
01081             with open(os.path.join(apport.report._whitelist_dir, 'README'), 'w') as fd:
01082                 fd.write('# Ignore file\n#/bin/bash\n')
01083 
01084             # accepts matching paths
01085             with open(os.path.join(apport.report._whitelist_dir, 'wl1'), 'w') as fd:
01086                 fd.write('/bin/bash\n')
01087             self.assertEqual(bash_rep.check_ignored(), False)
01088             self.assertEqual(crap_rep.check_ignored(), True)
01089 
01090             # also accept crap now
01091             with open(os.path.join(apport.report._whitelist_dir, 'wl_2'), 'w') as fd:
01092                 fd.write('/bin/crap\n')
01093             self.assertEqual(bash_rep.check_ignored(), False)
01094             self.assertEqual(crap_rep.check_ignored(), False)
01095 
01096             # only complete matches accepted
01097             with open(os.path.join(apport.report._whitelist_dir, 'wl1'), 'w') as fd:
01098                 fd.write('/bin/bas\n/bin/bashh\nbash\n')
01099             self.assertEqual(bash_rep.check_ignored(), True)
01100             self.assertEqual(crap_rep.check_ignored(), False)
01101         finally:
01102             shutil.rmtree(apport.report._whitelist_dir)
01103             apport.report._whitelist_dir = orig_whitelist_dir
01104             apport.report.apport.report._ignore_file = orig_ignore_file


The documentation for this class was generated from the following file: