Home Knowledge Base Concolic execution

Concolic execution (concrete + symbolic) is a hybrid program analysis technique that combines concrete execution with symbolic execution — running programs with actual input values while simultaneously tracking symbolic constraints, enabling more scalable path exploration than pure symbolic execution while maintaining systematic coverage.

What Is Concolic Execution?

How Concolic Execution Works

1. Initial Input: Start with a random or user-provided concrete input.

2. Concrete Execution: Run the program with the concrete input.

3. Symbolic Tracking: Simultaneously track symbolic constraints along the executed path.

4. Path Constraint Collection: Collect the sequence of branch conditions that led to this execution.

5. Constraint Negation: Negate one branch condition to explore an alternative path.

6. Constraint Solving: Solve the modified constraints to generate a new concrete input.

7. Iteration: Execute with the new input, repeat the process.

8. Coverage: Continue until desired coverage is achieved or time limit is reached.

Example: Concolic Execution

def test_function(x, y):
    if x > 0:          # Branch 1
        if y < 10:     # Branch 2
            return "A"
        else:
            return "B"
    else:
        return "C"

# Iteration 1: Concrete input x=5, y=3
# Concrete execution: x=5 > 0 (true), y=3 < 10 (true) → "A"
# Symbolic constraints: α > 0 AND β < 10
# Path explored: True, True

# Iteration 2: Negate last branch
# New constraints: α > 0 AND β >= 10
# Solve: α=5, β=10
# Concrete execution: x=5 > 0 (true), y=10 < 10 (false) → "B"
# Path explored: True, False

# Iteration 3: Negate first branch
# New constraints: α <= 0
# Solve: α=0, β=0
# Concrete execution: x=0 > 0 (false) → "C"
# Path explored: False

# Result: All 3 paths covered with 3 test inputs!

Concolic vs. Pure Symbolic Execution

Advantages of Concolic Execution

Concolic Execution Tools

Applications

Example: Finding Buffer Overflow

void process(char *input) {
    if (input[0] == 'M' &&
        input[1] == 'A' &&
        input[2] == 'G' &&
        input[3] == 'I' &&
        input[4] == 'C') {
        // Magic string found
        char buffer[10];
        strcpy(buffer, input + 5);  // Potential overflow
    }
}

// Random fuzzing struggles to find "MAGIC" prefix
// Concolic execution:
// Iteration 1: input = "AAAAA..." → fails first check
// Constraints: input[0] != 'M'
// Negate: input[0] == 'M', solve → input = "MAAAA..."

// Iteration 2: input = "MAAAA..." → fails second check
// Constraints: input[0] == 'M' AND input[1] != 'A'
// Negate: input[0] == 'M' AND input[1] == 'A', solve → input = "MAAAA..."

// ... continues until "MAGIC" is found ...
// Then explores overflow path with long input after "MAGIC"

Hybrid Fuzzing (Fuzzing + Concolic)

1. Start with coverage-guided fuzzing (fast, explores many paths). 2. When fuzzing gets stuck (no new coverage), use concolic execution. 3. Concolic execution generates inputs to get past complex checks. 4. Return to fuzzing with new inputs.

Challenges

Optimization Techniques

LLMs and Concolic Execution

Benefits

Limitations

Concolic execution is a practical and effective program analysis technique — it combines the best of concrete and symbolic execution to achieve systematic path exploration while handling real-world program complexity, making it widely used in automated testing and security analysis.

concolic executionsoftware engineering

Explore 500+ Semiconductor & AI Topics

From EUV lithography to CUDA optimization — search the full knowledge base or chat with our AI assistant.