Part of #1999 — soroban-emit-multifuzz-v2 campaign tracking issue
Solang version: confirmed on public v0.3.5 CLI (solang compile --target soroban)
Target: Soroban
Crash type: LLVM assertion failure (BranchInst::AssertOK), process aborts
Summary
Using a plain non-boolean variable (e.g. a uint32 parameter) as the condition of a ternary (?:) expression crashes with a raw LLVM assertion rather than a Rust-side panic or a clean diagnostic. The equivalent if statement with the same non-boolean variable is correctly caught during semantic analysis — the gap is specific to the ternary operator with a non-literal condition.
Minimal repro
contract Test {
function f(uint32 a, uint32 b) public returns (uint32) {
return a ? b : a;
}
}
Crash output
warning: function can be declared 'pure'
solang: llvm/lib/IR/Instructions.cpp:1367: void llvm::BranchInst::AssertOK(): Assertion `getCondition()->getType()->isIntegerTy(1) && "May only branch on boolean predicates!"' failed.
Aborted
Controls (confirm the gap is specific to ternary + non-literal condition)
if statement with the same non-bool variable — correctly rejected:
contract Test {
function f(uint32 a) public {
if (a) {
}
}
}
Clean error: conversion from uint32 to bool not possible.
Integer literal as ternary condition — correctly rejected:
contract Test {
function f(uint32 a, uint32 b) public returns (uint32) {
return 1 ? b : a;
}
}
Clean error: expected 'bool', found integer.
So if conditions are checked properly, and literal ternary conditions are checked properly — it's specifically a non-literal expression used as a ternary condition that slips through with zero validation and goes straight to LLVM, hitting LLVMBuildCondBr with a non-i1 value.
Related, previously filed reports
Sibling gaps in the same "ternary condition must be boolean" check:
- A rational/decimal literal used as a condition crashes with a different panic (
internal error: entered unreachable code) in Solang's own emit code — see sibling sub-issue.
- A void-returning call used as a condition crashes constant folding with a
Poison-related panic — see sibling sub-issue.
Found via fuzzing
Discovered via AFL++ fuzzing campaign (soroban-emit-multifuzz-v2), found while building controls for the rational-literal ternary-condition report.
Part of #1999 —
soroban-emit-multifuzz-v2campaign tracking issueSolang version: confirmed on public v0.3.5 CLI (
solang compile --target soroban)Target: Soroban
Crash type: LLVM assertion failure (
BranchInst::AssertOK), process abortsSummary
Using a plain non-boolean variable (e.g. a
uint32parameter) as the condition of a ternary (?:) expression crashes with a raw LLVM assertion rather than a Rust-side panic or a clean diagnostic. The equivalentifstatement with the same non-boolean variable is correctly caught during semantic analysis — the gap is specific to the ternary operator with a non-literal condition.Minimal repro
Crash output
Controls (confirm the gap is specific to ternary + non-literal condition)
ifstatement with the same non-bool variable — correctly rejected:Clean error:
conversion from uint32 to bool not possible.Integer literal as ternary condition — correctly rejected:
Clean error:
expected 'bool', found integer.So
ifconditions are checked properly, and literal ternary conditions are checked properly — it's specifically a non-literal expression used as a ternary condition that slips through with zero validation and goes straight to LLVM, hittingLLVMBuildCondBrwith a non-i1 value.Related, previously filed reports
Sibling gaps in the same "ternary condition must be boolean" check:
internal error: entered unreachable code) in Solang's own emit code — see sibling sub-issue.Poison-related panic — see sibling sub-issue.Found via fuzzing
Discovered via AFL++ fuzzing campaign (
soroban-emit-multifuzz-v2), found while building controls for the rational-literal ternary-condition report.