PLC Lint // static analysis

Real findings, dissected

5 bugs the compiler doesn't catch

A CODESYS project builds with zero errors — and ships with an uncalled timer, a truncated setpoint, and a divide by a variable that's sometimes zero. The syntax is valid; the behavior isn't. Here's what static analysis finds where the compiler stays silent.

8real boiler-house exports
62–86score out of 100
~10 secfrom upload to report
0lines stored on disk

Findings — by severity

uncalled-timer high · critical

Uncalled timer

VAR
    Pause_pump : TOF;
END_VAR

// .Q is used in the pump-start logic…
IF NOT Pause_pump.Q THEN Start_Pump(); END_IF
// …but the block is never called — the timer never ticks,
// Pause_pump.Q stays at its default forever.
Compiler: builds PLC Lint: caught

The block is declared and read, but never called — the inter-start pause simply doesn't work. Found on a real boiler-house project.

real-to-time-mul medium · warning

Setpoint truncated by REAL_TO_TIME

tPulse := REAL_TO_TIME(rSetpoint) * 10;
// REAL_TO_TIME treats the number as milliseconds and
// truncates BEFORE the multiply — the setpoint is gone.
Compiler: builds PLC Lint: caught

The classic “converting seconds to ms”. The multiply can't save it — the fraction is lost during the conversion.

div-by-zero high · critical

Divide by a zero variable

rAvg := rSum / iCount;
// iCount is 0 on an empty sample → runtime exception
// on site, not on the bench.
Compiler: builds PLC Lint: caught

The linter distinguishes a literal 0 divisor, a variable that's never assigned nonzero, or one assigned 0 with no later <> 0 guard. Type-aware: plain REAL division is not flagged — false positives were killed on purpose.

unreachable-branch high · critical

Unreachable IF/ELSIF branch

IF x >= 100 THEN
    Alarm_Low();
ELSIF x >= 120 THEN   // unreachable: >=120 already caught above
    Alarm_High();
END_IF
Compiler: builds PLC Lint: caught

The thresholds are in the wrong order — the high alarm never fires. The rule compares the full right-hand operand, so it won't confuse this with real hysteresis (T + 0.02).

watchdog-disabled medium · warning

Task watchdog disabled

<TaskSettings KindOfTask="Cyclic" Interval="t#10ms">
    <Watchdog Enabled="false" />   <!-- on EVERY task -->
</TaskSettings>
Compiler: builds PLC Lint: caught

Not a bug per se — but for a critical process a stalled scan won't get restarted. Better to see it in the summary than discover it on site.

Run your own export — see your score

Upload a .xml from CODESYS (Project → Export PLCopenXML), TwinCAT3, WAGO or ОВЕН. Report in ~10 seconds. Free, no signup for the first analysis, nothing stored.

…or see a live sample report →