Skip to content

Commit

Permalink
Add C frontend tests and move CPP test data (#1944)
Browse files Browse the repository at this point in the history
* move tests around

Signed-off-by: David Korczynski <david@adalogics.com>

* add C test for new frontend

Signed-off-by: David Korczynski <david@adalogics.com>

---------

Signed-off-by: David Korczynski <david@adalogics.com>
  • Loading branch information
DavidKorczynski authored Jan 9, 2025
1 parent 1802e81 commit 9cd9037
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 14 deletions.
36 changes: 35 additions & 1 deletion src/fuzz_introspector/frontends/frontend_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import tree_sitter_c
import yaml

from typing import Any
from typing import Any, Optional, Set

logger = logging.getLogger(name=__name__)

Expand Down Expand Up @@ -186,6 +186,40 @@ def extract_calltree(self,
line_number=line_number)
return line_to_print

def get_reachable_functions(
self,
source_code: Optional['SourceCodeFile'] = None,
function: Optional[str] = None,
visited_functions: Optional[set[str]] = None) -> Set[str]:
"""Gets the reachable frunctions from a given function."""
# Create calltree from a given function
# Find the function in the source code
if not visited_functions:
visited_functions = set()

if not function:
return visited_functions

if function in visited_functions:
return visited_functions

if not source_code:
source_code = self.find_source_with_func_def(function)

if not source_code:
return visited_functions

func = source_code.get_function_node(function)
if not func:
return visited_functions

callsites = func.callsites()
visited_functions.add(function)
for cs, _ in callsites:
visited_functions = self.get_reachable_functions(
function=cs, visited_functions=visited_functions)
return visited_functions

def find_source_with_func_def(self, target_function_name):
"""Finds the source code with a given function."""
source_codes_with_target = []
Expand Down
91 changes: 91 additions & 0 deletions src/test/data/source-code/c/simple-sample-1/fuzzer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int unreached_target2(const uint8_t *data) {
return 5;
}

char *global1 = "FUZZCAFE";
char *global2 = "FUZZKEYWORD";
int GLB2 = 0xbeef;

void unreached_target10(char *val) {
if (strcmp(val, global1) == 0) {
printf("Compare 1\n");
}
if (strcmp(val, global2) == 0) {
printf("Compare 15\n");
}
if (((int*)val) == GLB2) {
printf("Compare 3\n");
}
if (strcmp(val, "RABBIT") == 0) {
printf("Compare 4\n");
}
printf("Compare 2\n");
}

int unreached_target1(const uint8_t *data) {
if (data[0] == 0x11) {
return unreached_target2(data);
}
char *mc = (char*)malloc(12);
if (data[0] == 0x12) {
unreached_target10((char*)data);
return 0;
}
return 5;
}

int un(char *n1, char *n2, char *n3, char *n5, size_t s1) {
return 0;
}

int unreached_target3(const uint8_t *data, size_t *theval) {
if (data[0] == 0x11) {
return unreached_target1(data);
}

return 5;
}

char *d = "sf";
int target2(const uint8_t *data) {
if (data[0] == 0x41) return 1;
unreached_target1(d);
return 2;
}

int target3(const uint8_t *data) {
if (data[0] == 0x42) return 4;
return 3;
}

int fuzz_entry(const uint8_t *data, size_t size) {
int ret;
if (size == 2) {
ret = target2(data);
}
else if (size == 3) {
ret = target3(data);
}
else {
ret = 1;
}
return ret;
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 10) {
return 0;
}
char *kldfj = (char*)malloc(123);
char *nt = malloc(size+1);
memcpy(nt, data, size);
nt[size] = '\0';
fuzz_entry(nt, size);
return 0;
}

35 changes: 35 additions & 0 deletions src/test/test_frontends_c.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2025 Fuzz Introspector Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit testing script for the C frontend"""

from fuzz_introspector.frontends import oss_fuzz # noqa: E402


def test_simple_sample1():
callsites, project = oss_fuzz.analyse_folder(
language='c',
directory='src/test/data/source-code/c/simple-sample-1/',
entrypoint='LLVMFuzzerTestOneInput',
)

functions_reached = project.get_reachable_functions(
source_code=None,
function='LLVMFuzzerTestOneInput',
visited_functions=set())

assert 'target3' in functions_reached
assert 'unreached_target3' not in functions_reached

# Project check
assert len(project.get_source_codes_with_harnesses()) == 1
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit testing script for tree-sitter-frontend."""
"""Unit testing script for the CPP frontend"""

from fuzz_introspector.frontends import oss_fuzz # noqa: E402


def test_tree_sitter_cpp_sample1():
callsites, project = oss_fuzz.analyse_folder(
'c++',
'src/test/tree-sitter-frontend/cpp/test-project-1',
'src/test/data/source-code/cpp/test-project-1',
'LLVMFuzzerTestOneInput',
dump_output=False,
)
Expand All @@ -30,35 +30,35 @@ def test_tree_sitter_cpp_sample1():
# Callsite check
assert len(callsites[0].split('\n')) == 6
assert (' isPositive '
'src/test/tree-sitter-frontend/cpp/test-project-1/sample.cpp'
'src/test/data/source-code/cpp/test-project-1/sample.cpp'
in callsites[0])


def test_tree_sitter_cpp_sample2():
callsites, project = oss_fuzz.analyse_folder(
'c++',
'src/test/tree-sitter-frontend/cpp/test-project-2',
'src/test/data/source-code/cpp/test-project-2',
'LLVMFuzzerTestOneInput',
dump_output=False,
)

# Project check
# Project checkdata/source-code
assert len(project.get_source_codes_with_harnesses()) == 1

# Callsite check
assert len(callsites[0].split('\n')) == 13
assert (' RecursiveNamespace::fibonacci '
'src/test/tree-sitter-frontend/cpp/test-project-2/recursive.cpp'
'src/test/data/source-code/cpp/test-project-2/recursive.cpp'
in callsites[0])
assert (' File2Namespace::functionInFile2 '
'src/test/tree-sitter-frontend/cpp/test-project-2/crossfile.cpp'
'src/test/data/source-code/cpp/test-project-2/crossfile.cpp'
in callsites[0])


def test_tree_sitter_cpp_sample3():
callsites, project = oss_fuzz.analyse_folder(
'c++',
'src/test/tree-sitter-frontend/cpp/test-project-3',
'src/test/data/source-code/cpp/test-project-3',
'LLVMFuzzerTestOneInput',
dump_output=False,
)
Expand All @@ -69,17 +69,17 @@ def test_tree_sitter_cpp_sample3():
# Callsite check
assert len(callsites[0].split('\n')) == 14
assert (' std::reverse '
'src/test/tree-sitter-frontend/cpp/test-project-3/deep_chain.cpp'
'src/test/data/source-code/cpp/test-project-3/deep_chain.cpp'
in callsites[0])
assert (' DeepNamespace::level5 '
'src/test/tree-sitter-frontend/cpp/test-project-3/deep_chain.cpp'
'src/test/data/source-code/cpp/test-project-3/deep_chain.cpp'
in callsites[0])


def test_tree_sitter_cpp_sample4():
callsites, project = oss_fuzz.analyse_folder(
'c++',
'src/test/tree-sitter-frontend/cpp/test-project-4',
'src/test/data/source-code/cpp/test-project-4',
'LLVMFuzzerTestOneInput',
dump_output=False,
)
Expand All @@ -90,15 +90,15 @@ def test_tree_sitter_cpp_sample4():
# Callsite check
assert len(callsites[0].split('\n')) == 7
assert (' Level1::Level2::Level3::Level4::DeepClass::deepMethod2 '
'src/test/tree-sitter-frontend/cpp/test-project-4/deep_nested.cc'
'src/test/data/source-code/cpp/test-project-4/deep_nested.cc'
in callsites[0])


def test_frontend_reachability1():
"""Test reachability of a nested namespace."""
_, project = oss_fuzz.analyse_folder(
'c++',
'src/test/tree-sitter-frontend/cpp/test-project-4',
'src/test/data/source-code/cpp/test-project-4',
'LLVMFuzzerTestOneInput',
dump_output=False,
)
Expand Down

0 comments on commit 9cd9037

Please sign in to comment.