|
|
@ -60,11 +60,17 @@ def process_file(options):
|
|
|
|
Returns:
|
|
|
|
Returns:
|
|
|
|
A tuple containing:
|
|
|
|
A tuple containing:
|
|
|
|
- A list of objects whose lifetimes were completed
|
|
|
|
- A list of objects whose lifetimes were completed
|
|
|
|
|
|
|
|
(i.e., finished objects)
|
|
|
|
|
|
|
|
- A list of objects referenced after destruction
|
|
|
|
|
|
|
|
(i.e., invalid objects)
|
|
|
|
- A list of objects whose lifetimes were not completed
|
|
|
|
- A list of objects whose lifetimes were not completed
|
|
|
|
|
|
|
|
(i.e., leaked objects)
|
|
|
|
- A list of objects whose lifetimes are skewed
|
|
|
|
- A list of objects whose lifetimes are skewed
|
|
|
|
|
|
|
|
(i.e., Object history starting with an unusual ref count)
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
finished_objects = []
|
|
|
|
finished_objects = []
|
|
|
|
|
|
|
|
invalid_objects = []
|
|
|
|
leaked_objects = []
|
|
|
|
leaked_objects = []
|
|
|
|
skewed_objects = []
|
|
|
|
skewed_objects = []
|
|
|
|
current_objects = {}
|
|
|
|
current_objects = {}
|
|
|
@ -76,18 +82,33 @@ def process_file(options):
|
|
|
|
if not parsed_line:
|
|
|
|
if not parsed_line:
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
invalid = False
|
|
|
|
obj = parsed_line['addr']
|
|
|
|
obj = parsed_line['addr']
|
|
|
|
|
|
|
|
|
|
|
|
if obj not in current_objects:
|
|
|
|
if obj not in current_objects:
|
|
|
|
current_objects[obj] = {'log': [], 'curcount': 1,}
|
|
|
|
current_objects[obj] = {'log': [], 'curcount': 1}
|
|
|
|
if 'constructor' not in parsed_line['state']:
|
|
|
|
if 'constructor' in parsed_line['state']:
|
|
|
|
current_objects[obj]['curcount'] = parsed_line['state']
|
|
|
|
# This is the normal expected case
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
elif 'invalid' in parsed_line['state']:
|
|
|
|
|
|
|
|
invalid = True
|
|
|
|
|
|
|
|
current_objects[obj]['curcount'] = 0
|
|
|
|
|
|
|
|
if options.invalid:
|
|
|
|
|
|
|
|
invalid_objects.append((obj, current_objects[obj]))
|
|
|
|
|
|
|
|
elif 'destructor' in parsed_line['state']:
|
|
|
|
|
|
|
|
current_objects[obj]['curcount'] = 0
|
|
|
|
|
|
|
|
if options.skewed:
|
|
|
|
|
|
|
|
skewed_objects.append((obj, current_objects[obj]))
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
current_objects[obj]['curcount'] = int(
|
|
|
|
|
|
|
|
parsed_line['state'])
|
|
|
|
if options.skewed:
|
|
|
|
if options.skewed:
|
|
|
|
skewed_objects.append((obj, current_objects[obj]))
|
|
|
|
skewed_objects.append((obj, current_objects[obj]))
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
current_objects[obj]['curcount'] += int(parsed_line['delta'])
|
|
|
|
current_objects[obj]['curcount'] += int(parsed_line['delta'])
|
|
|
|
|
|
|
|
|
|
|
|
current_objects[obj]['log'].append("[%s] %s:%s %s: %s %s - [%s]" % (
|
|
|
|
current_objects[obj]['log'].append(
|
|
|
|
|
|
|
|
"[%s] %s:%s %s: %s %s - [%s]" % (
|
|
|
|
parsed_line['thread_id'],
|
|
|
|
parsed_line['thread_id'],
|
|
|
|
parsed_line['file'],
|
|
|
|
parsed_line['file'],
|
|
|
|
parsed_line['line'],
|
|
|
|
parsed_line['line'],
|
|
|
@ -96,15 +117,34 @@ def process_file(options):
|
|
|
|
parsed_line['tag'],
|
|
|
|
parsed_line['tag'],
|
|
|
|
parsed_line['state']))
|
|
|
|
parsed_line['state']))
|
|
|
|
|
|
|
|
|
|
|
|
if current_objects[obj]['curcount'] == 0:
|
|
|
|
# It is possible for curcount to go below zero if someone
|
|
|
|
if options.normal:
|
|
|
|
# unrefs an object by two or more when there aren't that
|
|
|
|
|
|
|
|
# many refs remaining. This condition abnormally finishes
|
|
|
|
|
|
|
|
# the object.
|
|
|
|
|
|
|
|
if current_objects[obj]['curcount'] <= 0:
|
|
|
|
|
|
|
|
if current_objects[obj]['curcount'] < 0:
|
|
|
|
|
|
|
|
current_objects[obj]['log'].append(
|
|
|
|
|
|
|
|
"[%s] %s:%s %s: %s %s - [%s]" % (
|
|
|
|
|
|
|
|
parsed_line['thread_id'],
|
|
|
|
|
|
|
|
parsed_line['file'],
|
|
|
|
|
|
|
|
parsed_line['line'],
|
|
|
|
|
|
|
|
parsed_line['function'],
|
|
|
|
|
|
|
|
"+0",
|
|
|
|
|
|
|
|
"Object abnormally finalized",
|
|
|
|
|
|
|
|
"**implied destructor**"))
|
|
|
|
|
|
|
|
# Highlight the abnormally finished object in the
|
|
|
|
|
|
|
|
# invalid section as well as reporting it in the normal
|
|
|
|
|
|
|
|
# finished section.
|
|
|
|
|
|
|
|
if options.invalid:
|
|
|
|
|
|
|
|
invalid_objects.append((obj, current_objects[obj]))
|
|
|
|
|
|
|
|
if not invalid and options.normal:
|
|
|
|
finished_objects.append((obj, current_objects[obj]))
|
|
|
|
finished_objects.append((obj, current_objects[obj]))
|
|
|
|
del current_objects[obj]
|
|
|
|
del current_objects[obj]
|
|
|
|
|
|
|
|
|
|
|
|
if options.leaks:
|
|
|
|
if options.leaks:
|
|
|
|
for key, lines in current_objects.iteritems():
|
|
|
|
for key, lines in current_objects.iteritems():
|
|
|
|
leaked_objects.append((key, lines))
|
|
|
|
leaked_objects.append((key, lines))
|
|
|
|
return (finished_objects, leaked_objects, skewed_objects)
|
|
|
|
return (finished_objects, invalid_objects, leaked_objects, skewed_objects)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_objects(objects, prefix=""):
|
|
|
|
def print_objects(objects, prefix=""):
|
|
|
@ -138,6 +178,10 @@ def main(argv=None):
|
|
|
|
parser.add_option("-f", "--file", action="store", type="string",
|
|
|
|
parser.add_option("-f", "--file", action="store", type="string",
|
|
|
|
dest="filepath", default="/var/log/asterisk/refs",
|
|
|
|
dest="filepath", default="/var/log/asterisk/refs",
|
|
|
|
help="The full path to the refs file to process")
|
|
|
|
help="The full path to the refs file to process")
|
|
|
|
|
|
|
|
parser.add_option("-i", "--suppress-invalid", action="store_false",
|
|
|
|
|
|
|
|
dest="invalid", default=True,
|
|
|
|
|
|
|
|
help="If specified, don't output invalid object "
|
|
|
|
|
|
|
|
"references")
|
|
|
|
parser.add_option("-l", "--suppress-leaks", action="store_false",
|
|
|
|
parser.add_option("-l", "--suppress-leaks", action="store_false",
|
|
|
|
dest="leaks", default=True,
|
|
|
|
dest="leaks", default=True,
|
|
|
|
help="If specified, don't output leaked objects")
|
|
|
|
help="If specified, don't output leaked objects")
|
|
|
@ -152,7 +196,8 @@ def main(argv=None):
|
|
|
|
|
|
|
|
|
|
|
|
(options, args) = parser.parse_args(argv)
|
|
|
|
(options, args) = parser.parse_args(argv)
|
|
|
|
|
|
|
|
|
|
|
|
if not options.leaks and not options.skewed and not options.normal:
|
|
|
|
if not options.invalid and not options.leaks and not options.normal \
|
|
|
|
|
|
|
|
and not options.skewed:
|
|
|
|
print >>sys.stderr, "All options disabled"
|
|
|
|
print >>sys.stderr, "All options disabled"
|
|
|
|
return -1
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
|
@ -162,9 +207,14 @@ def main(argv=None):
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
(finished_objects,
|
|
|
|
(finished_objects,
|
|
|
|
|
|
|
|
invalid_objects,
|
|
|
|
leaked_objects,
|
|
|
|
leaked_objects,
|
|
|
|
skewed_objects) = process_file(options)
|
|
|
|
skewed_objects) = process_file(options)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if options.invalid and len(invalid_objects):
|
|
|
|
|
|
|
|
print_objects(invalid_objects, "Invalid Referenced")
|
|
|
|
|
|
|
|
ret_code |= 4
|
|
|
|
|
|
|
|
|
|
|
|
if options.leaks and len(leaked_objects):
|
|
|
|
if options.leaks and len(leaked_objects):
|
|
|
|
print_objects(leaked_objects, "Leaked")
|
|
|
|
print_objects(leaked_objects, "Leaked")
|
|
|
|
ret_code |= 1
|
|
|
|
ret_code |= 1
|
|
|
|