cilium/cilium · error

evaluating branch: %w

Error message

evaluating branch: %w

What it means

predictBranch wraps errors from evalJumpOp when evaluating an immediate comparison between the resolved dst value and the branch's constant. This means the register resolved fine, but the jump opcode itself could not be evaluated.

Source

Thrown at pkg/bpf/analyze/reachability.go:456

	// field register contains the dereferenced value of the config variable.
	//
	// Example:
	//	0: LoadMapValue dst: r1, fd: 0 off: 4 <.rodata.config>
	//	2: LdXMemB dst: r2 src: r1 off: 0 imm: 0
	//	3: JNEImm dst: r2 off: 2 imm: 0
	case asm.ImmSource:
		dst, err := resolveRegister(bt, branch.Dst, vars)
		if errors.Is(err, errUnpredictable) {
			// Don't wrap err since this is a hot path.
			return false, err
		}
		if err != nil {
			return false, fmt.Errorf("resolving dst register %s: %w", branch.Dst, err)
		}

		jump, err := evalJumpOp(branch.OpCode, dst, branch.Constant)
		if err != nil {
			return false, fmt.Errorf("evaluating branch: %w", err)
		}

		return jump, nil

	// Register comparisons require finding both a map load and an immediate
	// load into the two registers used by the branch instruction.
	//
	// Example:
	//	0: LoadMapValue dst: r1, fd: 0 off: 4 <.rodata.config>
	//	2: LdXMemDW dst: r1 src: r1 off: 0 imm: 0
	//	3: LdImmDW dst: r2 imm: 42
	//	5: JGTReg dst: r1 src: r2 off: 2
	//
	// Note that src and reg may be swapped depending on the comparison op and the
	// compiler's mood. During initial testing, the config value was more often
	// found in dst.
	case asm.RegSource:
		dst, err := resolveRegister(bt.Clone(), branch.Dst, vars)

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Check branch.OpCode in the failing instruction and confirm evalJumpOp supports that jump operator.
  2. Add a case for the missing operator in evalJumpOp if you own the code.
  3. As a workaround, ensure such branches are classified as unpredictable (handled via unpredictableBlock) rather than reaching the evaluator.
Defensive patterns

Strategy: validation

Validate before calling

supported := map[asm.JumpOp]bool{
	asm.Ja: true, asm.JEq: true, asm.JNE: true, asm.JGT: true,
	asm.JGE: true, asm.JLT: true, asm.JLE: true, asm.JSGT: true,
	asm.JSGE: true, asm.JSLT: true, asm.JSLE: true,
}
if branch.OpCode.JumpOp() == 0 && !supported[branch.OpCode.JumpOp()] {
	// treat as unpredictable instead of evaluating
}

Type guard

func isSupportedJumpOp(op asm.OpCode) bool {
	switch op.JumpOp() {
	case asm.Ja, asm.JEq, asm.JNE, asm.JGT, asm.JGE, asm.JLT, asm.JLE,
		asm.JSet, asm.JSGT, asm.JSGE, asm.JSLT, asm.JSLE:
		return true
	}
	return false
}

Try / catch

jump, err := evalJumpOp(branch.OpCode, dst, branch.Constant)
if err != nil {
	return false, errUnpredictable // degrade to conservative visit
}

Prevention

When it happens

Trigger: evalJumpOp is given a jump OpCode it does not recognize or support (e.g. unsupported jump operators like JSET passed through this path, or a non-jump opcode reaching the evaluator).

Common situations: Compiler emits jump variants (e.g. JSET imm, 32-bit jump ops JA32) that evalJumpOp doesn't handle for the ImmSource path.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/496293c6bc9d4799. Report an issue: GitHub.