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

[Rust]: Add logic for handling rust projects #1818

Merged
merged 12 commits into from
Nov 18, 2024
Merged
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
70 changes: 70 additions & 0 deletions frontends/rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Rust frontend

This project provides a tool for analyzing a Rust project directory to extract information about functions and methods, excluding specified directories. It also identifies fuzz_target macros in any fuzzing harness and generates call tree files for these targets. The tool leverages the Syn crate for Abstract Syntax Tree (AST) parsing and provides its functionality through a set of Rust source files.

## How to run
```
cargo run -- $SRC
```

## How It Works

This tool operates in three primary phases:
1. Source analysis and function/method extraction
2. Call tree extraction, generation and output
3. Function data generation and output

The `main.rs` is the major entry points of the Rust frontend analyser. It manage the calls to `analyse.rs`, `call_tree.rs` and `generate_yaml.rs` separately to operates the three phases mentioned above.

## Source files

The `main.rs` script accepts a source directory path (or retrieves it from the environment variable `$SRC` in the OSS-Fuzz Docker image). It then passes the project source directory to `analyse.rs` for source analysis and function/method extraction.

The `analyse.rs` script performs both source analysis and function/method extraction (details provided below).

The `call_tree.rs` script identifies fuzzing harnesses (marked with the `fuzz_target` macro) in the specified source directory. It generates call graphs linking the functions extracted by `analyse.rs` to the function calls within each fuzzing harness's `fuzz_target` macro. The output is saved to `fuzzerLogFile-<fuzzing_harness_name>.data`.

The `generate_yaml.rs` script produces YAML files containing all the functions extracted from the project source directory by `analyse.rs`. The output is saved as `fuzzerLogFile-<fuzzing_harness_name>.data.yaml`.

### Source Analysis
The source analysis process targets to identify all rust source files from the project directory while excluding unnecessary files.

1. **Directory Traversal**: Uses Rust's `std::fs` and `walkdir` crates to traverse the project directory.
2. **File Filtering**: Ensures only `.rs` files are processed.
3. **Exclusion Handling**: Skips files within excluded directories.

### Function/Method Extraction
The function/method extraction process adopt the **Syn** crate from the rust framework to extract Abstract-Syntax-Tree (AST) of the project source code and extract all functions/methods from the source directory together with their information.

The **Syn** crate provides the following applications:
- **Parsing**: Converts Rust source code into an AST.
- **Traversal**: Provides utilities to traverse the AST and inspect specific nodes.
- **Extraction**: Enables extraction of detailed function and method information, including visibility, attributes, and more.

We integrate the **Syn** crate into our custom **FunctionAnalyser** to traverse functions and methods, extracting essential information for generating function elements, which the Fuzz-Introspector backend processes.

### 1. Parsing Source Files

The tool reads each Rust source file in the target directory, using **Syn**’s `syn::parse_file` to convert the code into an Abstract Syntax Tree (AST). This AST captures the complete structure, including functions, methods, and macros.

### 2. Traversing the AST

`FunctionAnalyser` traverses the AST to identify items of interest: functions (`ItemFn`) and methods (`ImplItemFn`) within implementation blocks (`ItemImpl`). This allows it to capture both standalone functions and associated methods.

### 3. Extracting Function Details

For each function or method, `FunctionAnalyser` extracts key details, including the name (`ident`), signature (parameters and return type), visibility (`Visibility`), and argument information (`FnArg`). These basic details are gathered during traversal.

### 4. Analysing Function Bodies

The tool analyses the function body (`Block`) to calculate cyclomatic complexity and identify function calls from `ExprCall` and `ExprMethodCall` nodes. These calls are stored in a `call_stack` to map functions and their invocations, supporting the generation of `callsites`, `functionUses`, and `functionDepth`.

### 5. Profiling Branches

`FunctionAnalyser` profiles conditional branches, focusing on `if` expressions (`ExprIf`). It builds `BranchProfileEntry` objects that capture branch details, including functions called within each branch. Currently, only `if` expressions are supported.

### 6. Post-Processing

After traversal, the tool calculates function depths by tracing call relationships and resolves fully qualified method names for accuracy. It finalises function use counts from the reverse call map, offering a detailed view of function utilisation.

By leveraging the **Syn** crate, `FunctionAnalyser` systematically extracts and analyses function and method data, enabling comprehensive code analysis.
1 change: 1 addition & 0 deletions frontends/rust/rust_function_analyser/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
13 changes: 13 additions & 0 deletions frontends/rust/rust_function_analyser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "rust_function_analyser"
version = "0.1.0"
edition = "2021"

[dependencies]
proc-macro2 = { version = "1.0", features = ["span-locations"] }
syn = { version = "2.0", features = ["full", "visit"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
quote = "1.0"
walkdir = "2.4"
Loading
Loading