Skip to content
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
1,499 changes: 1,499 additions & 0 deletions ossfuzz_py/README.md

Large diffs are not rendered by default.

90 changes: 85 additions & 5 deletions ossfuzz_py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,107 @@
historical fuzzing results, and execute customized fuzzing experiments.
"""

from .core.benchmark_manager import Benchmark, BenchmarkManager
try:
from .core.benchmark_manager import Benchmark, BenchmarkManager
except ImportError:
# Handle missing dependencies gracefully
Benchmark = None
BenchmarkManager = None
# Data models and enums
from .core.data_models import (CrashData, FuzzingEngine, ProjectConfig,
Sanitizer, Severity)
try:
from .core.data_models import (BuildHistoryData, CorpusHistoryData,
CoverageHistoryData, CrashData,
CrashHistoryData, FuzzingEngine,
HistoricalSummary, ProjectConfig, Sanitizer,
Severity, TimeSeriesData)
except ImportError:
# Handle missing dependencies gracefully
BuildHistoryData = CorpusHistoryData = CoverageHistoryData = None
CrashData = CrashHistoryData = FuzzingEngine = HistoricalSummary = None
ProjectConfig = Sanitizer = Severity = TimeSeriesData = None

# Core SDK - Main SDK class and modules
from .core.ossfuzz_manager import OSSFuzzManager
try:
from .core.ossfuzz_manager import OSSFuzzManager
from .core.ossfuzz_sdk import OSSFuzzSDK
except ImportError:
# Handle missing dependencies gracefully
OSSFuzzManager = OSSFuzzSDK = None
try:
from .data.storage_adapter import (FileStorageAdapter, GCSStorageAdapter,
StorageAdapter)
# Storage components
from .data.storage_manager import StorageManager
except ImportError:
# Handle missing dependencies gracefully
FileStorageAdapter = GCSStorageAdapter = StorageAdapter = None
StorageManager = None

# Error handling
from .errors import *

# History managers
try:
from .history import (BuildHistoryManager, CorpusHistoryManager,
CoverageHistoryManager, CrashHistoryManager,
HistoryManager)
except ImportError:
# Handle missing dependencies gracefully
BuildHistoryManager = CorpusHistoryManager = CoverageHistoryManager = None
CrashHistoryManager = HistoryManager = None

# Result management
try:
from .result import (AnalysisInfo, BenchmarkResult, BuildInfo,
CoverageAnalysis, CrashAnalysis, Result, ResultManager,
RunInfo, TrialResult)
except ImportError:
# Handle missing dependencies gracefully
AnalysisInfo = BenchmarkResult = BuildInfo = CoverageAnalysis = None
CrashAnalysis = Result = ResultManager = RunInfo = TrialResult = None

# Public API - All exports available to SDK clients
__all__ = [
# Core SDK - Main classes according to UML diagram
'OSSFuzzManager',
'OSSFuzzSDK',
'BenchmarkManager',
'Benchmark',

# Result management
'ResultManager',
'Result',
'BuildInfo',
'RunInfo',
'AnalysisInfo',
'TrialResult',
'BenchmarkResult',
'CoverageAnalysis',
'CrashAnalysis',

# History managers
'HistoryManager',
'BuildHistoryManager',
'CrashHistoryManager',
'CorpusHistoryManager',
'CoverageHistoryManager',

# Storage components
'StorageManager',
'StorageAdapter',
'FileStorageAdapter',
'GCSStorageAdapter',

# Data models and enums
'Severity',
'Sanitizer',
'Sanitizer',
'FuzzingEngine',
'BuildHistoryData',
'CrashHistoryData',
'CorpusHistoryData',
'CoverageHistoryData',
'TimeSeriesData',
'HistoricalSummary',

# Core error types and enums
'ErrorCode',
Expand Down
2 changes: 1 addition & 1 deletion ossfuzz_py/build/build_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import logging
from typing import Any, Dict, List, Optional

from ossfuzz_py import BuildConfigError
from ossfuzz_py.core.data_models import FuzzingEngine, ProjectConfig, Sanitizer
from ossfuzz_py.errors import BuildConfigError

# Configure module logger
logger = logging.getLogger('ossfuzz_sdk.build_config')
Expand Down
103 changes: 86 additions & 17 deletions ossfuzz_py/build/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@
from ossfuzz_py.build.build_config import BuildConfig
from ossfuzz_py.build.cloud_build_manager import CloudBuildManager
from ossfuzz_py.build.docker_manager import CommandResult, DockerManager
from ossfuzz_py.core.benchmark_manager import Benchmark
from ossfuzz_py.core.data_models import Sanitizer
from ossfuzz_py.data.storage_manager import StorageManager
from ossfuzz_py.execution.fuzz_target import FuzzTarget
# Import ResultManager for result storage
from ossfuzz_py.result.result_manager import ResultManager
from ossfuzz_py.result.results import BuildInfo, Result
from ossfuzz_py.utils.file_utils import FileUtils

# NOTE: Running-related constants have been moved to LocalRunner and CloudRunner
Expand All @@ -49,7 +53,7 @@
logger = logging.getLogger('ossfuzz_sdk.builder')


class Result:
class BuildResult:
"""Simple result class for build operations."""

def __init__(self,
Expand Down Expand Up @@ -99,7 +103,7 @@ def setup_environment(self) -> bool:
"""

@abstractmethod
def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> 'Result':
def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> 'BuildResult':
"""
Build a fuzz target with the specified sanitizer.

Expand Down Expand Up @@ -168,18 +172,23 @@ class LocalBuilder(Builder):
Docker, following the UML specification.
"""

def __init__(self, storage_manager: StorageManager, build_config: BuildConfig,
docker_manager: DockerManager):
def __init__(self,
storage_manager: StorageManager,
build_config: BuildConfig,
docker_manager: DockerManager,
result_manager: Optional[ResultManager] = None):
"""
Initialize the local builder.

Args:
storage_manager: Storage manager for artifacts
build_config: Build configuration
docker_manager: Docker manager for container operations
result_manager: Optional ResultManager for centralized result storage
"""
super().__init__(storage_manager, build_config)
self.docker_manager = docker_manager
self.result_manager = result_manager
self._artifacts: Dict[str, Path] = {}

self.logger.debug("Initialized LocalBuilder with Docker manager")
Expand All @@ -198,15 +207,19 @@ def setup_environment(self) -> bool:

def build(self,
target: FuzzTarget,
sanitizer: Sanitizer = Sanitizer.ADDRESS) -> Result:
sanitizer: Sanitizer = Sanitizer.ADDRESS,
benchmark_id: Optional[str] = None,
trial: int = 1) -> BuildResult:
"""Build a fuzz target with the specified sanitizer."""
try:
self.logger.info("Building target %s with sanitizer %s", target.name,
sanitizer.value)

# Prepare build environment
if not self.prepare_build_environment():
return Result(False, "Failed to prepare build environment")
build_result = BuildResult(False, "Failed to prepare build environment")
self._store_build_result(target, build_result, benchmark_id, trial)
return build_result

# Use the build_local method (focused only on building)
success, build_metadata = self.build_local(
Expand All @@ -216,7 +229,9 @@ def build(self,

if not success:
error_msg = build_metadata.get('error', 'Local build failed')
return Result(False, error_msg)
build_result = BuildResult(False, error_msg)
self._store_build_result(target, build_result, benchmark_id, trial)
return build_result

# # Store artifacts in storage manager
# for name, path in artifacts.items():
Expand All @@ -226,13 +241,20 @@ def build(self,
# self.storage_manager.store(
# f"{self.build_config.project_name}/{name}", data)

return Result(True,
"Build completed successfully",
metadata=build_metadata)
build_result = BuildResult(True,
"Build completed successfully",
metadata=build_metadata)

# Store result through ResultManager if available
self._store_build_result(target, build_result, benchmark_id, trial)

return build_result

except Exception as e:
self.logger.error("Build failed: %s", e)
return Result(False, f"Build failed: {e}")
build_result = BuildResult(False, f"Build failed: {e}")
self._store_build_result(target, build_result, benchmark_id, trial)
return build_result

def clean(self) -> bool:
"""Clean up build artifacts and temporary files."""
Expand Down Expand Up @@ -392,6 +414,53 @@ def build_local(self,
self.logger.info('Built %s locally successfully.', benchmark_target_name)
return True, build_metadata

def _store_build_result(self, target: FuzzTarget, build_result: BuildResult,
benchmark_id: Optional[str], trial: int) -> None:
"""Store build result through ResultManager if available."""
try:
# Create BuildInfo from build result
build_info = BuildInfo(
compiles=build_result.success,
compile_log=build_result.message or '',
errors=[]
if build_result.success else [build_result.message or 'Build failed'],
binary_exists=build_result.success,
is_function_referenced=build_result.success,
fuzz_target_source=target.source_code,
build_script_source=target.build_script or '',
)

# Create minimal benchmark for the result
benchmark = Benchmark(
project=self.build_config.project_name,
language=target.language,
function_signature=
f'int {target.name}(const uint8_t* data, size_t size)',
function_name=target.name,
return_type='int',
target_path='',
id=benchmark_id or target.name,
)

# Create Result object for storage
result_obj = Result(
benchmark=benchmark,
work_dirs='',
trial=trial,
build_info=build_info,
)

# Store through ResultManager
if self.result_manager:
self.result_manager.store_result(benchmark_id or target.name,
result_obj)
self.logger.debug("Stored build result for %s through ResultManager",
benchmark_id or target.name)

except Exception as e:
self.logger.warning(
"Failed to store build result through ResultManager: %s", e)

def build_target_local(self,
generated_project: str,
sanitizer: str = 'address') -> bool:
Expand Down Expand Up @@ -458,15 +527,15 @@ def setup_environment(self) -> bool:
self.logger.error("Failed to setup cloud environment: %s", e)
return False

def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> Result:
def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> BuildResult:
"""Build a fuzz target using cloud build."""
try:
self.logger.info("Starting cloud build for target %s with sanitizer %s",
target.name, sanitizer.value)

# Prepare build environment
if not self.prepare_build_environment():
return Result(False, "Failed to prepare build environment")
return BuildResult(False, "Failed to prepare build environment")

# Use the build_cloud method (focused only on building)
success, build_metadata = self.build_cloud(
Expand All @@ -477,7 +546,7 @@ def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> Result:

if not success:
error_msg = build_metadata.get('error', 'Cloud build failed')
return Result(False, error_msg)
return BuildResult(False, error_msg)

# Process build artifacts
artifacts = self._process_cloud_build_artifacts(build_metadata)
Expand All @@ -494,12 +563,12 @@ def build(self, target: FuzzTarget, sanitizer: Sanitizer) -> Result:
# TODO: Running should be handled separately by CloudRunner
# The build_metadata contains all necessary information for the runner

return Result(True, "Cloud build completed successfully", artifacts,
build_metadata)
return BuildResult(True, "Cloud build completed successfully", artifacts,
build_metadata)

except Exception as e:
self.logger.error("Cloud build failed: %s", e)
return Result(False, f"Cloud build failed: {e}")
return BuildResult(False, f"Cloud build failed: {e}")

def build_cloud(self,
source_code: str,
Expand Down
Loading