Annotation Framework

Lotus provides annotations and summary tables for modeling library and external function behavior across alias, taint, and bug-checking analyses.

Dedicated module pages:

Position Tracking

The position tracking system provides abstractions for identifying function arguments and return values in annotations.

Location: include/Annotation/ArgPosition.h

Components:

  • ArgPosition – Represents a specific function argument position

  • RetPosition – Represents the return value position

  • APosition – Union type that can represent either an argument or return position

Usage:

#include <Annotation/ArgPosition.h>
using namespace annotation;

// Create argument positions
APosition arg0 = APosition::getArgPosition(0);
APosition arg1 = APosition::getAfterArgPosition(1);  // After argument 1
APosition ret = APosition::getReturnPosition();

// Query position type
if (ret.isReturnPosition()) {
    // Handle return position
}
if (arg0.isArgPosition()) {
    const ArgPosition& pos = arg0.getAsArgPosition();
    uint8_t idx = pos.getArgIndex();
    bool after = pos.isAfterArgPosition();
}

ModRef Annotations

Modification and reference behavior annotations track how functions access memory through their arguments and return values.

Location: include/Annotation/ModRef/

Components:

  • ModRefType – Enumeration: Mod (modification) or Ref (reference/read)

  • ModRefClass – Enumeration: DirectMemory or ReachableMemory

  • ModRefEffect – Represents a single mod/ref effect with type, class, and position

  • ModRefEffectSummary – Collection of mod/ref effects for a function

  • ExternalModRefTable – Table mapping function names to their mod/ref summaries

  • ExternalModRefTablePrinter – Utility for printing mod/ref tables

Usage:

#include <Annotation/ModRef/ExternalModRefTable.h>
#include <Annotation/ModRef/ModRefEffect.h>
using namespace annotation;

// Load mod/ref table from file
ExternalModRefTable table = ExternalModRefTable::loadFromFile("modref.spec");

// Lookup function effects
llvm::StringRef funcName = "strcpy";
const ModRefEffectSummary* summary = table.lookup(funcName);

if (summary) {
    for (const auto& effect : *summary) {
        ModRefType type = effect.getType();
        ModRefClass mClass = effect.getClass();
        APosition pos = effect.getPosition();

        if (effect.isModEffect() && effect.onDirectMemory()) {
            // Function modifies direct memory
        }
    }
}

// Print table
ExternalModRefTablePrinter printer(llvm::errs());
printer.printTable(table);

Pointer Annotations

Pointer annotations specify how functions allocate, copy, or exit with pointers.

Location: include/Annotation/Pointer/

Components:

  • PointerEffectType – Enumeration: Alloc, Copy, or Exit

  • PointerAllocEffect – Represents pointer allocation with optional size position

  • CopySource – Source of a copy operation (Value, DirectMemory, ReachableMemory, Null, Universal, Static)

  • CopyDest – Destination of a copy operation (Value, DirectMemory, ReachableMemory)

  • PointerCopyEffect – Represents a copy operation from source to destination

  • PointerExitEffect – Represents program exit

  • PointerEffect – Union type representing any pointer effect

  • PointerEffectSummary – Collection of pointer effects for a function

  • ExternalPointerTable – Table mapping function names to their pointer effect summaries

  • ExternalPointerTablePrinter – Utility for printing pointer tables

Usage:

#include <Annotation/Pointer/ExternalPointerTable.h>
#include <Annotation/Pointer/PointerEffect.h>
using namespace annotation;

// Load pointer table from file
ExternalPointerTable table = ExternalPointerTable::loadFromFile("ptr.spec");

// Lookup function effects
llvm::StringRef funcName = "malloc";
const PointerEffectSummary* summary = table.lookup(funcName);

if (summary) {
    for (const auto& effect : *summary) {
        switch (effect.getType()) {
            case PointerEffectType::Alloc: {
                const PointerAllocEffect& alloc = effect.getAsAllocEffect();
                if (alloc.hasSizePosition()) {
                    APosition sizePos = alloc.getSizePosition();
                }
                break;
            }
            case PointerEffectType::Copy: {
                const PointerCopyEffect& copy = effect.getAsCopyEffect();
                const CopyDest& dest = copy.getDest();
                const CopySource& src = copy.getSource();
                break;
            }
            case PointerEffectType::Exit:
                // Function exits program
                break;
        }
    }
}

// Print table
ExternalPointerTablePrinter printer(llvm::errs());
printer.printTable(table);

Taint Analysis Annotations

Taint analysis annotations specify information flow and taint propagation through functions.

Location: include/Annotation/Taint/

Components:

  • TaintSpec – Specification for taint location (ARG, AFTER_ARG, RET), access mode (VALUE, DEREF), and taint type (TAINTED, UNINITIALIZED)

  • PipeSpec – Specification for taint propagation from source to destination

  • FunctionTaintConfig – Complete taint configuration for a single function (sources, sinks, pipes)

  • TaintConfig – Complete taint configuration containing all function specs

  • TaintConfigParser – Parser for taint specification files (.spec format)

  • TaintConfigManager – Singleton manager for taint configurations with function name normalization

Usage:

#include <Annotation/Taint/TaintConfigManager.h>
using namespace taint_config;

// Load configuration (singleton pattern)
TaintConfigManager& manager = TaintConfigManager::getInstance();
manager.load_config("config/taint.spec");
// Or use convenience namespace functions
load_config("config/taint.spec");
load_default_config();  // Tries multiple standard paths

// Check if function is a source or sink
bool isSrc = is_source("read");
bool isSink = is_sink("printf");
bool isIgnored = is_ignored("memcpy");

// Check LLVM call instructions
llvm::CallInst* call = ...;
if (is_source(call)) {
    // Function call is a taint source
}

// Get detailed function configuration
const FunctionTaintConfig* funcConfig = get_function_config("strcpy");
if (funcConfig) {
    // Access source_specs, sink_specs, pipe_specs
}

// Normalize function names (handles platform prefixes)
std::string normalized = normalize_name("__strcpy_chk");  // Returns "strcpy"

// Dump configuration
dump_config(llvm::errs());

// Get statistics
size_t numSources = get_source_count();
size_t numSinks = get_sink_count();