Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(HIS): add CALLS his metric #59

Open
wants to merge 3 commits into
base: wip/his-metrics
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ RUN apt-get update && apt-get install -y \
tree \
vim \
nano \
device-tree-compiler
device-tree-compiler \
cflow

# Install python packages
RUN pip3 install \
Expand All @@ -56,7 +57,8 @@ RUN pip3 install \
pyspellchecker \
ROPgadget \
capstone \
GitPython
GitPython \
anytree

# Install javascript packages
RUN npm install -g cspell@latest
Expand Down
88 changes: 85 additions & 3 deletions his_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,39 @@

import sys
import argparse
import os
from anytree import Node

def traverse(node, threshold, failed_nodes=None):
"""
Helper function to traverse the tree create in the process_calls function
"""
if failed_nodes is None:
failed_nodes = []

# Initialize a variable to True. This will remain True if all checks pass.
is_new_node = True

# Check each node in failed_nodes
for f_node in failed_nodes:
# If the current node's name is the same as a name in failed_nodes
if node.name == f_node.name:
# Set is_new_node to False and break the loop
is_new_node = False
break

# If the node has more children than the threshold and is_new_node is still True
if len(node.children) > threshold and is_new_node:
# Add the node to failed_nodes
failed_nodes.append(node)

# For each child of the current node
for child in node.children:
# Recursively traverse the child's subtree, passing the current list of nodes
traverse(child, threshold, failed_nodes)


return failed_nodes

def process_calling(files, threshold):
"""
Expand All @@ -21,12 +54,61 @@ def process_calling(files, threshold):

def process_calls(files, threshold):
"""
Process the calls metric
Process the number of called functions. This function checks the number of functions does a
particular function calls. If the number of 'calls' in a function exceeds the defined
threshold, an error message is printed and the error count is incremented.

Args:
files: A list of file paths to check for 'calls'.
threshold: The maximum number of permitted 'calls' in a function.

Returns:
The number of files that exceed the number of 'calls'.
"""

print(f"Processing CALLS metric with threshold [0-{threshold}] for files: {', '.join(files)}")
metric_fail = 0
nodes = {}
root = None

print("--------------------------------------------")
print(f"Processing CALLS metric with threshold [0-{threshold}]")
print("--------------------------------------------")

# Process each file
for file in files:
# Run 'cflow' on the file and split the output into lines
lines = os.popen(f"cflow -l {file}").read().split('\n')

trees = []
for line in lines:

if not line.strip():
continue # Skip empty lines

# Extract level and func/file name
lvl, descriptor = line.split('}', 1)
lvl = int(lvl.strip('{').strip())

# Create root node or child node based on level
if lvl == 0:
root = Node(descriptor) # Create a new root node
trees.append(root)
nodes = {0: root} # Reset nodes dictionary for the new tree
else:
parent = nodes[lvl - 1]
# Update the current node and its parent reference
nodes[lvl] = Node(descriptor, parent=parent)

# Check the number of calls in each tree
for root in trees:
nodes_failed = traverse(root, threshold)
for node in nodes_failed:
func_name = node.name.split(')', 1)[0].strip() + ')'
print(f"At {file} has {len(node.children)} calls in function {func_name}")
metric_fail += 1

return metric_fail

return 0

def process_comf(files, threshold):
"""
Expand Down
Loading