mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 03:20:57 +00:00
astobj2.c/refcounter.py: Fix to deal with invalid object refs.
* Make astob2 REF_DEBUG output an invalid object line when an invalid ao2 object ref/unref is attempted. This is similar to the constructor/destructor lines. * Fixed refcounter.py to handle skewed objects that have constructor/destructor states. * Made refcounter.py highlight the invalid ao2 object refs by putting them in their own section of the processed output file. * Made refcounter.py highlight unreffing an object by more than one that results in a negative ref count and the object being destroyed. The abnormally destroyed object is reported in the invalid and finalized object sections of the output. Review: https://reviewboard.asterisk.org/r/3971/ ........ Merged revisions 423349 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 423400 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 423416 from http://svn.asterisk.org/svn/asterisk/branches/12 ........ Merged revisions 423418 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@423422 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -60,11 +60,17 @@ def process_file(options):
|
||||
Returns:
|
||||
A tuple containing:
|
||||
- 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
|
||||
(i.e., leaked objects)
|
||||
- A list of objects whose lifetimes are skewed
|
||||
(i.e., Object history starting with an unusual ref count)
|
||||
"""
|
||||
|
||||
finished_objects = []
|
||||
invalid_objects = []
|
||||
leaked_objects = []
|
||||
skewed_objects = []
|
||||
current_objects = {}
|
||||
@@ -76,35 +82,69 @@ def process_file(options):
|
||||
if not parsed_line:
|
||||
continue
|
||||
|
||||
invalid = False
|
||||
obj = parsed_line['addr']
|
||||
|
||||
if obj not in current_objects:
|
||||
current_objects[obj] = {'log': [], 'curcount': 1,}
|
||||
if 'constructor' not in parsed_line['state']:
|
||||
current_objects[obj]['curcount'] = parsed_line['state']
|
||||
current_objects[obj] = {'log': [], 'curcount': 1}
|
||||
if 'constructor' in 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:
|
||||
skewed_objects.append((obj, current_objects[obj]))
|
||||
else:
|
||||
current_objects[obj]['curcount'] += int(parsed_line['delta'])
|
||||
|
||||
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'],
|
||||
parsed_line['delta'],
|
||||
parsed_line['tag'],
|
||||
parsed_line['state']))
|
||||
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'],
|
||||
parsed_line['delta'],
|
||||
parsed_line['tag'],
|
||||
parsed_line['state']))
|
||||
|
||||
if current_objects[obj]['curcount'] == 0:
|
||||
if options.normal:
|
||||
# It is possible for curcount to go below zero if someone
|
||||
# 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]))
|
||||
del current_objects[obj]
|
||||
|
||||
if options.leaks:
|
||||
for key, lines in current_objects.iteritems():
|
||||
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=""):
|
||||
@@ -138,6 +178,10 @@ def main(argv=None):
|
||||
parser.add_option("-f", "--file", action="store", type="string",
|
||||
dest="filepath", default="/var/log/asterisk/refs",
|
||||
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",
|
||||
dest="leaks", default=True,
|
||||
help="If specified, don't output leaked objects")
|
||||
@@ -152,7 +196,8 @@ def main(argv=None):
|
||||
|
||||
(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"
|
||||
return -1
|
||||
|
||||
@@ -162,9 +207,14 @@ def main(argv=None):
|
||||
|
||||
try:
|
||||
(finished_objects,
|
||||
invalid_objects,
|
||||
leaked_objects,
|
||||
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):
|
||||
print_objects(leaked_objects, "Leaked")
|
||||
ret_code |= 1
|
||||
|
@@ -485,8 +485,14 @@ int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *fil
|
||||
}
|
||||
|
||||
if (ref_log && user_data) {
|
||||
if (obj && old_refcount + delta == 0) {
|
||||
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n", user_data, delta, ast_get_tid(), file, line, func, tag);
|
||||
if (!obj) {
|
||||
/* Invalid object: Bad magic number. */
|
||||
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
|
||||
user_data, delta, ast_get_tid(), file, line, func, tag);
|
||||
fflush(ref_log);
|
||||
} else if (old_refcount + delta == 0) {
|
||||
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
|
||||
user_data, delta, ast_get_tid(), file, line, func, tag);
|
||||
fflush(ref_log);
|
||||
} else if (delta != 0) {
|
||||
fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"),
|
||||
|
Reference in New Issue
Block a user