Report — DemoBoiler · PLC Lint
← check another file<br>Report: DemoBoiler
demo.xml · version n/a ·<br>POUs: 7 · globals: 49
👋<br>This is a demo report on a synthetic project — to show what you'll get. No need to upload your own code. Want to check yours?
🔎<br>1 POU in graphical languages (CFC 1) — line-based checks were NOT applied to them; names are partially covered (occurrences in blocks/expressions). This is a tool limitation, not a sign these POUs are clean.
Quality score: 0/100
Save the report to your profile — you'll build a verified quality track. The code is not stored, only the aggregate.
Analyze your export
Acceptance protocol →
10
Critical
10
Warning
13
Minor
Severity distribution
Critical 10<br>Warning 10<br>Minor 13
Top rules
dead-pou
naming
div-by-zero
implicit-check-disabled
family-gap
copy-paste
Every rule has a noise? button — click it if the rule gives irrelevant hits on your code. The signal helps us tune the checks: lower the severity, narrow the condition or disable extras. Your code is not sent.
Critical 10 findings
CFC: division by a literal zero<br>1 · cfc-div-zero<br>noise?
In graphical code (CFC/FBD) the divisor of a DIV/MOD block is wired to a literal constant 0 — a runtime exception when the block executes. Checked against the connection graph.
Suggested fixes
Wire a variable/setpoint into the divisor input instead of the literal 0 — usually a debug stub left behind.<br>If the divisor can go to zero at runtime — pick a safe value before DIV/MOD (a SEL on a compare-with-0).
CfcDiv<br>— the divisor of the DIV block is wired to a literal 0 → a guaranteed division by zero
Implicit check does not protect<br>1 · broken-implicit-check<br>noise?
An implicit check function (Check…) exists, but its protective logic is gutted: an empty body, or the check (divisor=0 / bounds) removed. The runtime calls it, but it catches nothing — a false sense of safety, more dangerous than its absence.
Suggested fixes
Restore the protective logic: CheckDivReal must test IF divisor = 0 THEN … := 1;<br>CheckBounds/CheckRange… must clamp the value to lower..upper. Compare with the default CODESYS implementation.
CheckBounds<br>— no lower/upper bounds comparison — the value is not clamped — the check exists but doesn't work (a false sense of safety)
Division by a literal zero<br>2 · div-by-zero<br>noise?
Division or MOD by a literal zero — a guaranteed runtime exception (division by zero) whenever this line is reached.
Suggested fixes
Remove the division by 0 — probably a typo in the divisor.<br>If the divisor can be zero dynamically — guard it: IF d <> 0 THEN r := x / d; END_IF
DivZeroVar:1<br>— division by znever — the variable is 0 (init 0/empty) and never assigned → a guaranteed division by zero
qa := 5 / znever;
Main:2<br>— division/MOD by a literal zero
d := d / 0;
Global name typo (gvl.*)<br>1 · undeclared-global<br>noise?
A gvl. reference has no declaration in the GVL — almost always a typo; the variable is silently created or the code won't compile.
Suggested fixes
Check the spelling against the GVL declaration (case, underscores, digits).<br>If the variable is really needed — add it to the GVL with a type and a comment.
Main<br>— gvl.missing — not in the GVL (likely a typo)
Array index out of bounds<br>1 · array-bounds<br>noise?
A constant index falls outside the declared ARRAY[lo..hi] bounds — reaching this line reads/writes memory that isn't yours. Without active implicit checks the runtime won't intercept it. Checked for one-dimensional arrays with numeric bounds and a literal index.
Suggested fixes
Bring the index into the declared range or widen the array bounds.<br>Check before access: IF idx >= LO AND idx
Main:1<br>— arr[5] out of bounds [0..3]
arr[5] := 1;
Infinite loop with no exit<br>1 · infinite-loop<br>noise?
WHILE TRUE / REPEAT … UNTIL FALSE with no EXIT or RETURN inside — the scan never finishes: the task blocks and the watchdog fires (and if the watchdog is off, the controller stalls). In a PLC, long processing is spread across scans, not spun in a loop.
Suggested fixes
Add an exit condition and EXIT, or bound it with an iteration counter.<br>Split heavy processing across scans — an infinite loop trips the task watchdog.
Main:11<br>— WHILE TRUE without EXIT/RETURN
Channel never written — gap in a channel family<br>2 · family-gap<br>noise?
A field is declared for every channel in a family (boilers 1–4, pumps 1–3) and used by all of them but exactly one, where it is never written. The usual cause: the block was copied from a neighbouring channel and left unfinished. The compiler stays silent — the variable exists and the type is right, nobody just writes to it. On site this shows up as “boiler 4 never reports alarms” while the other three work, and it never reproduces on the bench. The rule relies on declarations: if the field is not declared for that channel, it is different hardware rather than a gap, and nothing is reported.
Suggested fixes
Check that channel's block: an assignment was most likely copied from the...