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.