~brian-murray/ubuntu/natty/apport/rr-if-idontknow

« back to all changes in this revision

Viewing changes to apport/report.py

  • Committer: Martin Pitt
  • Date: 2011-02-04 14:41:46 UTC
  • mfrom: (1369.34.52 trunk)
  • Revision ID: martin.pitt@canonical.com-20110204144146-o0fq0kh4shzsutr3
new upstream release 1.17.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
from xml.parsers.expat import ExpatError
17
17
 
18
18
from problem_report import ProblemReport
19
 
import fileutils
20
 
from packaging_impl import impl as packaging
 
19
import apport
 
20
import apport.fileutils
 
21
from apport.packaging_impl import impl as packaging
21
22
 
22
23
_data_dir = os.environ.get('APPORT_DATA_DIR','/usr/share/apport')
23
24
_hook_dir = '%s/package-hooks/' % (_data_dir)
56
57
    '''
57
58
    try:
58
59
        return open(path).read().strip()
59
 
    except (OSError, IOError), e:
 
60
    except (OSError, IOError) as e:
60
61
        return 'Error: ' + str(e)
61
62
 
62
63
def _read_maps(pid):
67
68
    '''
68
69
    maps = 'Error: unable to read /proc maps file'
69
70
    try:
70
 
        maps = file('/proc/%d/maps' % pid).read().strip()
71
 
    except (OSError,IOError), e:
 
71
        maps = open('/proc/%d/maps' % pid).read().strip()
 
72
    except (OSError,IOError) as e:
72
73
        return 'Error: ' + str(e)
73
74
    return maps
74
75
 
84
85
    if sp.returncode == 0:
85
86
        return out
86
87
    else:
87
 
       raise OSError, 'Error: command %s failed with exit code %i: %s' % (
88
 
           str(command), sp.returncode, err)
 
88
       raise OSError('Error: command %s failed with exit code %i: %s' % (
 
89
           str(command), sp.returncode, err))
89
90
 
90
91
def _check_bug_pattern(report, pattern):
91
92
    '''Check if given report matches the given bug pattern XML DOM node.
177
178
                self['ProblemType'] == 'KernelCrash'):
178
179
                package = self['Package']
179
180
            else:
180
 
                package = fileutils.find_file_package(self['ExecutablePath'])
 
181
                package = apport.fileutils.find_file_package(self['ExecutablePath'])
181
182
            if not package:
182
183
                return
183
184
 
333
334
        self['ProcMaps'] = _read_maps(int(pid))
334
335
        try:
335
336
            self['ExecutablePath'] = os.readlink('/proc/' + pid + '/exe')
336
 
        except OSError, e:
 
337
        except OSError as e:
337
338
            if e.errno == errno.ENOENT:
338
 
                raise ValueError, 'invalid process'
 
339
                raise ValueError('invalid process')
339
340
            else:
340
341
                raise
341
342
        for p in ('rofs', 'rwfs', 'squashmnt', 'persistmnt'):
599
600
            except StopIteration:
600
601
                return True
601
602
            except:
602
 
                print >> sys.stderr, 'hook %s crashed:' % hook
 
603
                apport.error('hook %s crashed:', hook)
603
604
                traceback.print_exc()
604
605
                pass
605
606
 
620
621
                except StopIteration:
621
622
                    return True
622
623
                except:
623
 
                    print >> sys.stderr, 'hook %s crashed:' % hook
 
624
                    apport.error('hook %s crashed:', hook)
624
625
                    traceback.print_exc()
625
626
                    pass
626
627
 
641
642
                except StopIteration:
642
643
                    return True
643
644
                except:
644
 
                    print >> sys.stderr, 'hook %s crashed:' % hook
 
645
                    apport.error('hook %s crashed:', hook)
645
646
                    traceback.print_exc()
646
647
                    pass
647
648
 
714
715
        else:
715
716
            try:
716
717
                dom = xml.dom.minidom.parse(ifpath)
717
 
            except ExpatError, e:
718
 
                raise ValueError, '%s has invalid format: %s' % (_ignore_file, str(e))
 
718
            except ExpatError as e:
 
719
                raise ValueError('%s has invalid format: %s' % (_ignore_file, str(e)))
719
720
 
720
721
        # remove whitespace so that writing back the XML does not accumulate
721
722
        # whitespace
1091
1092
#
1092
1093
 
1093
1094
import unittest, shutil, signal, time
1094
 
from cStringIO import StringIO
 
1095
try:
 
1096
    from cStringIO import StringIO
 
1097
except ImportError:
 
1098
    from io import StringIO
1095
1099
 
1096
1100
class _T(unittest.TestCase):
1097
1101
    def test_add_package_info(self):
1106
1110
        pr.add_package_info('bash')
1107
1111
        self.assertEqual(pr['Package'], 'bash ' + bashversion.strip())
1108
1112
        self.assertEqual(pr['SourcePackage'], 'bash')
1109
 
        self.assert_('libc' in pr['Dependencies'])
 
1113
        self.assertTrue('libc' in pr['Dependencies'])
1110
1114
 
1111
1115
        # test without specifying a package, but with ExecutablePath
1112
1116
        pr = Report()
1115
1119
        pr.add_package_info()
1116
1120
        self.assertEqual(pr['Package'], 'bash ' + bashversion.strip())
1117
1121
        self.assertEqual(pr['SourcePackage'], 'bash')
1118
 
        self.assert_('libc' in pr['Dependencies'])
 
1122
        self.assertTrue('libc' in pr['Dependencies'])
1119
1123
        # check for stray empty lines
1120
 
        self.assert_('\n\n' not in pr['Dependencies'])
1121
 
        self.assert_(pr.has_key('PackageArchitecture'))
 
1124
        self.assertTrue('\n\n' not in pr['Dependencies'])
 
1125
        self.assertTrue(pr.has_key('PackageArchitecture'))
1122
1126
 
1123
1127
        pr = Report()
1124
1128
        pr['ExecutablePath'] = '/nonexisting'
1125
1129
        pr.add_package_info()
1126
 
        self.assert_(not pr.has_key('Package'))
 
1130
        self.assertTrue(not pr.has_key('Package'))
1127
1131
 
1128
1132
    def test_add_os_info(self):
1129
1133
        '''add_os_info().'''
1130
1134
 
1131
1135
        pr = Report()
1132
1136
        pr.add_os_info()
1133
 
        self.assert_(pr['Uname'].startswith('Linux'))
1134
 
        self.assert_(type(pr['DistroRelease']) == type(''))
1135
 
        self.assert_(pr['Architecture'])
 
1137
        self.assertTrue(pr['Uname'].startswith('Linux'))
 
1138
        self.assertTrue(type(pr['DistroRelease']) == type(''))
 
1139
        self.assertTrue(pr['Architecture'])
1136
1140
 
1137
1141
    def test_add_user_info(self):
1138
1142
        '''add_user_info().'''
1139
1143
 
1140
1144
        pr = Report()
1141
1145
        pr.add_user_info()
1142
 
        self.assert_(pr.has_key('UserGroups'))
 
1146
        self.assertTrue(pr.has_key('UserGroups'))
1143
1147
 
1144
1148
        # double-check that user group names are removed
1145
1149
        for g in pr['UserGroups'].split():
1146
 
            self.assert_(grp.getgrnam(g).gr_gid < 1000)
1147
 
        self.assert_(grp.getgrgid(os.getgid()).gr_name not in pr['UserGroups'])
 
1150
            self.assertTrue(grp.getgrnam(g).gr_gid < 1000)
 
1151
        self.assertTrue(grp.getgrgid(os.getgid()).gr_name not in pr['UserGroups'])
1148
1152
 
1149
1153
    def test_add_proc_info(self):
1150
1154
        '''add_proc_info().'''
1159
1163
        self.assertEqual(pr.pid, None)
1160
1164
        pr.add_proc_info()
1161
1165
        self.assertEqual(pr.pid, os.getpid())
1162
 
        self.assert_(set(['ProcEnviron', 'ProcMaps', 'ProcCmdline',
 
1166
        self.assertTrue(set(['ProcEnviron', 'ProcMaps', 'ProcCmdline',
1163
1167
            'ProcMaps']).issubset(set(pr.keys())), 'report has required fields')
1164
 
        self.assert_('LANG='+os.environ['LANG'] in pr['ProcEnviron'])
1165
 
        self.assert_('USER' not in pr['ProcEnviron'])
1166
 
        self.assert_('PWD' not in pr['ProcEnviron'])
 
1168
        self.assertTrue('LANG='+os.environ['LANG'] in pr['ProcEnviron'])
 
1169
        self.assertTrue('USER' not in pr['ProcEnviron'])
 
1170
        self.assertTrue('PWD' not in pr['ProcEnviron'])
1167
1171
 
1168
1172
        # check with one additional safe environment variable
1169
1173
        pr = Report()
1170
1174
        pr.add_proc_info(extraenv=['PWD'])
1171
 
        self.assert_('USER' not in pr['ProcEnviron'])
1172
 
        self.assert_('PWD='+os.environ['PWD'] in pr['ProcEnviron'])
 
1175
        self.assertTrue('USER' not in pr['ProcEnviron'])
 
1176
        self.assertTrue('PWD='+os.environ['PWD'] in pr['ProcEnviron'])
1173
1177
 
1174
1178
        # check process from other user
1175
1179
        assert os.getuid() != 0, 'please do not run this test as root for this check.'
1176
1180
        pr = Report()
1177
1181
        self.assertRaises(OSError, pr.add_proc_info, 1) # EPERM for init process
1178
1182
        self.assertEqual(pr.pid, 1)
1179
 
        self.assert_('init' in pr['ProcStatus'], pr['ProcStatus'])
1180
 
        self.assert_(pr['ProcEnviron'].startswith('Error:'), pr['ProcEnviron'])
1181
 
        self.assert_(not pr.has_key('InterpreterPath'))
 
1183
        self.assertTrue('init' in pr['ProcStatus'], pr['ProcStatus'])
 
1184
        self.assertTrue(pr['ProcEnviron'].startswith('Error:'), pr['ProcEnviron'])
 
1185
        self.assertTrue(not pr.has_key('InterpreterPath'))
1182
1186
 
1183
1187
        # check escaping of ProcCmdline
1184
1188
        p = subprocess.Popen(['cat', '/foo bar', '\\h', '\\ \\', '-'],
1194
1198
        p.communicate('\n')
1195
1199
        self.assertEqual(pr['ProcCmdline'], 'cat /foo\ bar \\\\h \\\\\\ \\\\ -')
1196
1200
        self.assertEqual(pr['ExecutablePath'], '/bin/cat')
1197
 
        self.assert_(not pr.has_key('InterpreterPath'))
 
1201
        self.assertTrue(not pr.has_key('InterpreterPath'))
1198
1202
        self.assertTrue('/bin/cat' in pr['ProcMaps'])
1199
1203
        self.assertTrue('[stack]' in pr['ProcMaps'])
1200
1204
 
1223
1227
        pr = Report()
1224
1228
        pr.add_proc_info(pid=p.pid)
1225
1229
        p.communicate('\n')
1226
 
        self.assert_(pr['ExecutablePath'].endswith('bin/zgrep'))
 
1230
        self.assertTrue(pr['ExecutablePath'].endswith('bin/zgrep'))
1227
1231
        self.assertEqual(pr['InterpreterPath'],
1228
1232
            os.path.realpath(open(pr['ExecutablePath']).readline().strip()[2:]))
1229
1233
        self.assertTrue('[stack]' in pr['ProcMaps'])
1235
1239
sys.stdin.readline()
1236
1240
''')
1237
1241
        os.close(fd)
1238
 
        os.chmod(testscript, 0755)
 
1242
        os.chmod(testscript, 0o755)
1239
1243
        p = subprocess.Popen([testscript], stdin=subprocess.PIPE,
1240
1244
            stderr=subprocess.PIPE, close_fds=True)
1241
1245
        assert p.pid
1247
1251
        p.communicate('\n')
1248
1252
        os.unlink(testscript)
1249
1253
        self.assertEqual(pr['ExecutablePath'], testscript)
1250
 
        self.assert_('python' in pr['InterpreterPath'])
 
1254
        self.assertTrue('python' in pr['InterpreterPath'])
1251
1255
        self.assertTrue('python' in pr['ProcMaps'])
1252
1256
        self.assertTrue('[stack]' in pr['ProcMaps'])
1253
1257
 
1274
1278
        r = Report()
1275
1279
        r.add_proc_environ(pid=p.pid)
1276
1280
        p.communicate('')
1277
 
        self.assert_('PATH=(custom, no user)' in r['ProcEnviron'], 
 
1281
        self.assertTrue('PATH=(custom, no user)' in r['ProcEnviron'], 
1278
1282
            'PATH is customized without user paths')
1279
1283
 
1280
1284
        # user paths
1284
1288
        r = Report()
1285
1289
        r.add_proc_environ(pid=p.pid)
1286
1290
        p.communicate('')
1287
 
        self.assert_('PATH=(custom, user)' in r['ProcEnviron'], 
 
1291
        self.assertTrue('PATH=(custom, user)' in r['ProcEnviron'], 
1288
1292
            'PATH is customized with user paths')
1289
1293
 
1290
1294
    def test_check_interpreted(self):
1459
1463
        return pr
1460
1464
 
1461
1465
    def _validate_gdb_fields(self,pr):
1462
 
        self.assert_(pr.has_key('Stacktrace'))
1463
 
        self.assert_(pr.has_key('ThreadStacktrace'))
1464
 
        self.assert_(pr.has_key('StacktraceTop'))
1465
 
        self.assert_(pr.has_key('Registers'))
1466
 
        self.assert_(pr.has_key('Disassembly'))
1467
 
        self.assert_('(no debugging symbols found)' not in pr['Stacktrace'])
1468
 
        self.assert_('Core was generated by' not in pr['Stacktrace'], pr['Stacktrace'])
1469
 
        self.assert_(not re.match(r'(?s)(^|.*\n)#0  [^\n]+\n#0  ',
 
1466
        self.assertTrue(pr.has_key('Stacktrace'))
 
1467
        self.assertTrue(pr.has_key('ThreadStacktrace'))
 
1468
        self.assertTrue(pr.has_key('StacktraceTop'))
 
1469
        self.assertTrue(pr.has_key('Registers'))
 
1470
        self.assertTrue(pr.has_key('Disassembly'))
 
1471
        self.assertTrue('(no debugging symbols found)' not in pr['Stacktrace'])
 
1472
        self.assertTrue('Core was generated by' not in pr['Stacktrace'], pr['Stacktrace'])
 
1473
        self.assertTrue(not re.match(r'(?s)(^|.*\n)#0  [^\n]+\n#0  ',
1470
1474
                                  pr['Stacktrace']))
1471
 
        self.assert_('#0  0x' in pr['Stacktrace'])
1472
 
        self.assert_('#1  0x' in pr['Stacktrace'])
1473
 
        self.assert_('#0  0x' in pr['ThreadStacktrace'])
1474
 
        self.assert_('#1  0x' in pr['ThreadStacktrace'])
1475
 
        self.assert_('Thread 1 (' in pr['ThreadStacktrace'])
1476
 
        self.assert_(len(pr['StacktraceTop'].splitlines()) <= 5)
 
1475
        self.assertTrue('#0  0x' in pr['Stacktrace'])
 
1476
        self.assertTrue('#1  0x' in pr['Stacktrace'])
 
1477
        self.assertTrue('#0  0x' in pr['ThreadStacktrace'])
 
1478
        self.assertTrue('#1  0x' in pr['ThreadStacktrace'])
 
1479
        self.assertTrue('Thread 1 (' in pr['ThreadStacktrace'])
 
1480
        self.assertTrue(len(pr['StacktraceTop'].splitlines()) <= 5)
1477
1481
 
1478
1482
    def test_add_gdb_info(self):
1479
1483
        '''add_gdb_info() with core dump file reference.'''
1497
1501
}
1498
1502
''')
1499
1503
        self._validate_gdb_fields(pr)
1500
 
        self.assert_('Cannot access memory at address 0x0' in pr['Disassembly'], pr['Disassembly'])
 
1504
        self.assertTrue('Cannot access memory at address 0x0' in pr['Disassembly'], pr['Disassembly'])
1501
1505
        self.failIf ('AssertionMessage' in pr)
1502
1506
 
1503
1507
    def test_add_gdb_info_load(self):
1523
1527
        pr.load(open(rep.name))
1524
1528
        pr['Signal'] = '1'
1525
1529
        pr.add_hooks_info('fake_ui')
1526
 
        self.assert_('SegvAnalysis' not in pr.keys())
 
1530
        self.assertTrue('SegvAnalysis' not in pr.keys())
1527
1531
 
1528
1532
        pr = Report()
1529
1533
        pr.load(open(rep.name))
1530
1534
        pr.add_hooks_info('fake_ui')
1531
 
        self.assert_('Skipped: missing required field "Architecture"' in pr['SegvAnalysis'],
 
1535
        self.assertTrue('Skipped: missing required field "Architecture"' in pr['SegvAnalysis'],
1532
1536
                     pr['SegvAnalysis'])
1533
1537
 
1534
1538
        pr.add_os_info()
1535
1539
        pr.add_hooks_info('fake_ui')
1536
 
        self.assert_('Skipped: missing required field "ProcMaps"' in pr['SegvAnalysis'],
 
1540
        self.assertTrue('Skipped: missing required field "ProcMaps"' in pr['SegvAnalysis'],
1537
1541
                     pr['SegvAnalysis'])
1538
1542
 
1539
1543
        pr.add_proc_info()
1540
1544
        pr.add_hooks_info('fake_ui')
1541
 
        self.assert_('not located in a known VMA region' in pr['SegvAnalysis'],
 
1545
        self.assertTrue('not located in a known VMA region' in pr['SegvAnalysis'],
1542
1546
                     pr['SegvAnalysis'])
1543
1547
 
1544
1548
    def test_add_gdb_info_script(self):
1556
1560
ulimit -c unlimited
1557
1561
kill -SEGV $$
1558
1562
''')
1559
 
            os.chmod(script, 0755)
 
1563
            os.chmod(script, 0o755)
1560
1564
 
1561
1565
            # call script and verify that it gives us a proper ELF core dump
1562
1566
            assert subprocess.call([script]) != 0
1573
1577
            os.unlink(script)
1574
1578
 
1575
1579
        self._validate_gdb_fields(pr)
1576
 
        self.assert_('libc.so' in pr['Stacktrace'] or 'in execute_command' in pr['Stacktrace'])
 
1580
        self.assertTrue('libc.so' in pr['Stacktrace'] or 'in execute_command' in pr['Stacktrace'])
1577
1581
 
1578
1582
    def test_add_gdb_info_abort(self):
1579
1583
        '''add_gdb_info() with SIGABRT/assert()
1596
1600
ulimit -c unlimited
1597
1601
$0.bin 2>/dev/null
1598
1602
''')
1599
 
            os.chmod(script, 0755)
 
1603
            os.chmod(script, 0o755)
1600
1604
 
1601
1605
            # call script and verify that it gives us a proper ELF core dump
1602
1606
            assert subprocess.call([script]) != 0
1613
1617
            os.unlink('core')
1614
1618
 
1615
1619
        self._validate_gdb_fields(pr)
1616
 
        self.assert_("<stdin>:2: main: Assertion `1 < 0' failed." in
 
1620
        self.assertTrue("<stdin>:2: main: Assertion `1 < 0' failed." in
1617
1621
                pr['AssertionMessage'], pr['AssertionMessage'])
1618
1622
        self.failIf(pr['AssertionMessage'].startswith('$'), pr['AssertionMessage'])
1619
1623
        self.failIf('= 0x' in pr['AssertionMessage'], pr['AssertionMessage'])
1638
1642
ulimit -c unlimited
1639
1643
LIBC_FATAL_STDERR_=1 $0.bin aaaaaaaaaaaaaaaa 2>/dev/null
1640
1644
''')
1641
 
            os.chmod(script, 0755)
 
1645
            os.chmod(script, 0o755)
1642
1646
 
1643
1647
            # call script and verify that it gives us a proper ELF core dump
1644
1648
            assert subprocess.call([script]) != 0
1655
1659
            os.unlink('core')
1656
1660
 
1657
1661
        self._validate_gdb_fields(pr)
1658
 
        self.assert_("** buffer overflow detected ***: %s.bin terminated" % (script) in
 
1662
        self.assertTrue("** buffer overflow detected ***: %s.bin terminated" % (script) in
1659
1663
                pr['AssertionMessage'], pr['AssertionMessage'])
1660
1664
        self.failIf(pr['AssertionMessage'].startswith('$'), pr['AssertionMessage'])
1661
1665
        self.failIf('= 0x' in pr['AssertionMessage'], pr['AssertionMessage'])
1676
1680
ulimit -c unlimited
1677
1681
$0.bin 2>/dev/null
1678
1682
''')
1679
 
            os.chmod(script, 0755)
 
1683
            os.chmod(script, 0o755)
1680
1684
 
1681
1685
            # call script and verify that it gives us a proper ELF core dump
1682
1686
            assert subprocess.call([script]) != 0
2020
2024
        self.failIf(r.has_useful_stacktrace())
2021
2025
 
2022
2026
        r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so'
2023
 
        self.assert_(r.has_useful_stacktrace())
 
2027
        self.assertTrue(r.has_useful_stacktrace())
2024
2028
 
2025
2029
        r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()'
2026
 
        self.assert_(r.has_useful_stacktrace())
 
2030
        self.assertTrue(r.has_useful_stacktrace())
2027
2031
 
2028
2032
        r['StacktraceTop'] = 'read () from /lib/libc.6.so\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()\n?? ()'
2029
 
        self.assert_(r.has_useful_stacktrace())
 
2033
        self.assertTrue(r.has_useful_stacktrace())
2030
2034
 
2031
2035
        r['StacktraceTop'] = 'read () from /lib/libc.6.so\n?? ()\nfoo (i=1) from /usr/lib/libfoo.so\n?? ()\n?? ()'
2032
2036
        self.failIf(r.has_useful_stacktrace())
2121
2125
Restarting AWN usually solves this issue'''
2122
2126
 
2123
2127
        t = report.standard_title()
2124
 
        self.assert_(t.startswith('apport-gtk crashed with'))
2125
 
        self.assert_(t.endswith('setup_chooser()'))
 
2128
        self.assertTrue(t.startswith('apport-gtk crashed with'))
 
2129
        self.assertTrue(t.endswith('setup_chooser()'))
2126
2130
 
2127
2131
        # Python crash at top level in module
2128
2132
        report = Report()
2366
2370
        del r['Signal']
2367
2371
        r['Traceback'] = '''Traceback (most recent call last):
2368
2372
  File "test.py", line 7, in <module>
2369
 
    print _f(5)
 
2373
    print(_f(5))
2370
2374
  File "test.py", line 5, in _f
2371
2375
    return g_foo00(x+1)
2372
2376
  File "test.py", line 2, in g_foo00