-
Notifications
You must be signed in to change notification settings - Fork 0
Public API and Library Mode
Hugo edited this page Feb 26, 2026
·
1 revision
The analyzer can be embedded as a C++ library in other tools. The public API is defined in include/StackUsageAnalyzer.hpp.
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;
};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;
};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;
};Combined result:
struct AnalysisResult
{
AnalysisConfig config;
std::vector<FunctionResult> functions;
std::vector<Diagnostic> diagnostics;
};Analyze an already-loaded LLVM module:
AnalysisResult analyzeModule(llvm::Module& mod, const AnalysisConfig& config);Convenience: load a .ll file and analyze:
AnalysisResult analyzeFile(
const std::string& filename,
const AnalysisConfig& config,
llvm::LLVMContext& ctx,
llvm::SMDiagnostic& err);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 = "");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;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;
}cmake -S extern-project -B extern-project/build
cmake --build extern-project/build -j./extern-project/build/sa_consumer \
test/alloca/oversized-constant.c \
build/compile_commands.json \
--mode=abi --analysis-profile=fast --warnings-only --jobs=4include(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.
| Value | Description |
|---|---|
IR |
Pure LLVM IR stack sizes |
ABI |
Includes ABI calling convention overhead |
| Value | Description |
|---|---|
Fast |
Skips large functions, limits GEP/store analysis |
Full |
Complete analysis, no limits |
| Value | Numeric | Description |
|---|---|---|
Info |
0 | Informational |
Warning |
1 | Potential issue |
Error |
2 | Definite issue |
| 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 |