1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
#
# This file is part of darktable,
# Copyright (C) 2022 darktable developers.
#
# darktable is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# darktable is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with darktable. If not, see <http://www.gnu.org/licenses/>.
#
# Read each IOP file, parse it for buffer allocs, and check if we have a corresponding free
import os
import re
directory = "../src/iop/"
alloc_regex = r"([a-zA-Z0-9_\-\>\.\[\]]+) = (dt_|c|m|dt_opencl_)alloc.*\(.+\)"
def find_call_and_line(elem, file, directory):
line_number = 0
f = open(os.path.join(directory, file), "r")
# find the line(s) in file
for line in f:
line_number += 1
if elem in line:
print("\t\t line", line_number, ":", elem.strip())
f.close()
for file in sorted(os.listdir(directory)):
if file.endswith(".c") or file.endswith(".h"):
f = open(os.path.join(directory, file), "r")
content = f.read()
# Find all allocs and extract the name of the pointer to the allocation
matches = re.finditer(alloc_regex, content, re.MULTILINE)
safe_allocs = 0
faulty_allocs = 0
suspicious_allocs = 0
print("%s" % file)
for matchNum, match in enumerate(matches):
# Get the name of the pointer to the allocation
variable_name = match.group(1)
alloc_type = match.group(2)
# Look how many times the variable is allocated
variable_alloc_regex = " %s = %salloc.*\(.+\)" % (variable_name, alloc_type)
matches2 = re.findall(variable_alloc_regex, content, re.MULTILINE)
allocs = len(matches2)
matches2 = set(matches2)
# Look how many times the variable is freed
variable_free_regex = r""
buffer_type = ""
if(alloc_type == "dt_opencl_"):
variable_free_regex = ".*release_mem_object.*\(%s\)" % variable_name
buffer_type = "OpenCL"
else:
variable_free_regex = " \S*free.*\(%s\)" % variable_name
buffer_type = "C"
matches3 = re.findall(variable_free_regex, content, re.MULTILINE)
frees = len(matches3)
matches3 = set(matches3)
# Note that for OpenCL, we may have more than one free for each alloc because of the error go-to
if(frees < allocs and frees == 0):
print("\tERROR: %s buffer `%s` is allocated %i time(s) but never freed" % (buffer_type, variable_name, allocs))
for elem in matches2:
find_call_and_line(elem, file, directory)
for elem in matches3:
find_call_and_line(elem, file, directory)
faulty_allocs += 1
elif(frees < allocs and frees > 0):
print("\tWARNING: %s buffer `%s` is allocated %i time(s) but freed %i time(s)" % (buffer_type, variable_name, allocs, frees))
for elem in matches2:
find_call_and_line(elem, file, directory)
for elem in matches3:
find_call_and_line(elem, file, directory)
suspicious_allocs += 1
else:
safe_allocs += 1
msg_type = "INFO"
if(suspicious_allocs > 0):
msg_type = "WARNING"
if(faulty_allocs > 0):
msg_type = "ERROR"
print("\t%s: %i safe alloc(s) detected over %i\n" % (msg_type, safe_allocs, safe_allocs + faulty_allocs + suspicious_allocs))
f.close()
|