Skip to content

Public API and Library Mode

Hugo edited this page Feb 26, 2026 · 1 revision

Public API and Library Mode

The analyzer can be embedded as a C++ library in other tools. The public API is defined in include/StackUsageAnalyzer.hpp.


Core Types

AnalysisConfig

Key fields of the configuration struct (abridged):

struct AnalysisConfig
{
    AnalysisMode mode = AnalysisMode::IR;           // IR or ABI
    AnalysisProfile profile = AnalysisProfile::Full; // Fast or Full
    StackSize stackLimit = 8ull * 1024ull * 1024ull; // 8 MiB default
    bool quiet = false;
    bool warningsOnly = false;
    std::vector<std::string> extraCompileArgs;       // -I, -D, etc.
    unsigned jobs = 1;
    bool timing = false;

    // Filters
    std::vector<std::string> onlyFiles;
    std::vector<std::string> onlyDirs;
    std::vector<std::string> excludeDirs;
    std::vector<std::string> onlyFunctions;
    bool includeSTL = false;

    // Models
    std::string escapeModelPath;
    std::string resourceModelPath;

    // Cross-TU
    bool resourceCrossTU = true;
    std::string resourceSummaryCacheDir = ".cache/resource-lifetime";
    bool resourceSummaryMemoryOnly = false;
    bool uninitializedCrossTU = true;

    // Compile database
    std::shared_ptr<const analysis::CompilationDatabase> compilationDatabase;
    bool compdbFast = false;

    // Debug
    std::string dumpIRPath;
    bool dumpFilter = false;
};

FunctionResult

Per-function analysis result:

struct FunctionResult
{
    std::string filePath;
    std::string name;
    StackSize localStack = 0;
    StackSize maxStack = 0;
    bool localStackUnknown = false;
    bool maxStackUnknown = false;
    bool hasDynamicAlloca = false;
    bool isRecursive = false;
    bool hasInfiniteSelfRecursion = false;
    bool exceedsLimit = false;
};

Diagnostic

Issue diagnostic:

struct Diagnostic
{
    std::string filePath;
    std::string funcName;
    unsigned line = 0;
    unsigned column = 0;
    unsigned startLine = 0;
    unsigned startColumn = 0;
    unsigned endLine = 0;
    unsigned endColumn = 0;
    DiagnosticSeverity severity = DiagnosticSeverity::Warning;
    DescriptiveErrorCode errCode = DescriptiveErrorCode::None;
    std::string ruleId;
    double confidence = -1.0;
    std::string cweId;
    std::vector<std::string> variableAliasingVec;
    std::string message;
};

AnalysisResult

Combined result:

struct AnalysisResult
{
    AnalysisConfig config;
    std::vector<FunctionResult> functions;
    std::vector<Diagnostic> diagnostics;
};

API Functions

analyzeModule

Analyze an already-loaded LLVM module:

AnalysisResult analyzeModule(llvm::Module& mod, const AnalysisConfig& config);

analyzeFile

Convenience: load a .ll file and analyze:

AnalysisResult analyzeFile(
    const std::string& filename,
    const AnalysisConfig& config,
    llvm::LLVMContext& ctx,
    llvm::SMDiagnostic& err);

toJson / toSarif

Serialize results:

std::string toJson(const AnalysisResult& result, const std::string& inputFile);
std::string toJson(const AnalysisResult& result, const std::vector<std::string>& inputFiles);

std::string toSarif(
    const AnalysisResult& result,
    const std::string& inputFile,
    const std::string& toolName = "coretrace-stack-analyzer",
    const std::string& toolVersion = "0.1.0",
    const std::string& baseDir = "");

CLI Parser Bridge

Reuse analyzer-style CLI arguments from your own tool:

#include "cli/ArgParser.hpp"

// From a command string
auto parsed = ctrace::stack::cli::parseCommandLine(
    "--mode=abi --analysis-profile=fast --warnings-only --jobs=4"
);

// From argc/argv
auto parsed = ctrace::stack::cli::parseArguments(argc, argv);

if (parsed.status == ctrace::stack::cli::ParseStatus::Error)
{
    // handle parsed.error
}

ctrace::stack::AnalysisConfig cfg = parsed.parsed.config;

Example: Library Consumer

A complete example is in extern-project/:

#include "StackUsageAnalyzer.hpp"
#include "cli/ArgParser.hpp"
#include <llvm/IR/LLVMContext.h>

int main(int argc, char** argv)
{
    // Parse arguments using analyzer's CLI parser
    auto parsed = ctrace::stack::cli::parseArguments(argc, argv);
    auto cfg = parsed.parsed.config;

    // Analyze
    llvm::LLVMContext ctx;
    llvm::SMDiagnostic err;
    auto result = ctrace::stack::analyzeFile("input.c", cfg, ctx, err);

    // Output as JSON
    std::cout << ctrace::stack::toJson(result, "input.c");

    return 0;
}

Building

cmake -S extern-project -B extern-project/build
cmake --build extern-project/build -j

Running

./extern-project/build/sa_consumer \
  test/alloca/oversized-constant.c \
  build/compile_commands.json \
  --mode=abi --analysis-profile=fast --warnings-only --jobs=4

CMake Integration

FetchContent

include(FetchContent)
FetchContent_Declare(
    stack-analyzer
    GIT_REPOSITORY https://github.com/CoreTrace/coretrace-stack-analyzer.git
    GIT_TAG main
)
FetchContent_MakeAvailable(stack-analyzer)

target_link_libraries(my_tool PRIVATE coretrace::stack_usage_analyzer_lib)

The library target coretrace::stack_usage_analyzer_lib automatically brings in LLVM, coretrace-compiler, and coretrace-logger dependencies.


Enums

AnalysisMode

Value Description
IR Pure LLVM IR stack sizes
ABI Includes ABI calling convention overhead

AnalysisProfile

Value Description
Fast Skips large functions, limits GEP/store analysis
Full Complete analysis, no limits

DiagnosticSeverity

Value Numeric Description
Info 0 Informational
Warning 1 Potential issue
Error 2 Definite issue

DescriptiveErrorCode

Value Description
StackBufferOverflow Out-of-bounds stack buffer access
NegativeStackIndex Negative index on stack buffer
VLAUsage Variable-length array detected
StackPointerEscape Stack address leaked
MemcpyWithStackDest memcpy/memset overflow on stack buffer
MultipleStoresToStackBuffer Multiple writes to same buffer
AllocaUserControlled User-controlled alloca size
AllocaTooLarge Oversized alloca
AllocaUsageWarning Dynamic alloca usage
InvalidBaseReconstruction Unsafe pointer arithmetic
ConstParameterNotModified Parameter could be const
SizeMinusOneWrite Off-by-one buffer access
DuplicateIfCondition Duplicate condition in if-else
UninitializedLocalRead Read before initialization
StackFrameTooLarge Stack exceeds limit
ResourceLifetimeIssue Resource leak or double release

Clone this wiki locally