Findings — по важности
uncalled-timer
high · критично
Невызванный таймер
VAR
Pause_nasos : TOF;
END_VAR
// .Q используется в логике пуска насоса…
IF NOT Pause_nasos.Q THEN Start_Pump(); END_IF
// …но сам блок нигде не вызван — таймер не тикает,
// Pause_nasos.Q навсегда в дефолте.
✓Компилятор: собирается
⚠PLC Lint: поймал
Блок объявлен и читается, но не вызывается — пауза между пусками не работает. Найдено на реальном проекте котельной.
real-to-time-mul
medium · внимание
Усечённая уставка через REAL_TO_TIME
tPulse := REAL_TO_TIME(rSetpoint) * 10;
// REAL_TO_TIME трактует число как миллисекунды
// и режет дробь ДО умножения — уставка уехала в мусор.
✓Компилятор: собирается
⚠PLC Lint: поймал
Классика «переводил секунды в миллисекунды». Домножение уже не спасает — дробь потеряна на конвертации.
div-by-zero
high · критично
Деление на переменную-ноль
rAvg := rSum / iCount;
// iCount при пустой выборке = 0 → рантайм-исключение
// на объекте, а не на стенде.
✓Компилятор: собирается
⚠PLC Lint: поймал
Линтер различает: делитель — литеральный 0, переменная, которая никогда не присваивается ненулём, или присваивается 0 без проверки <> 0. Типо-осознанно: обычное деление REAL он не трогает — давили ложняки специально.
unreachable-branch
high · критично
Недостижимая ветвь IF/ELSIF
IF x >= 100 THEN
Alarm_Low();
ELSIF x >= 120 THEN // недостижимо: >=120 уже поймано выше
Alarm_High();
END_IF
✓Компилятор: собирается
⚠PLC Lint: поймал
Порядок порогов перепутан — верхняя авария никогда не сработает. Правило сравнивает полный правый операнд, чтобы не путать это с нормальным гистерезисом (T + 0.02).
watchdog-disabled
medium · внимание
Сторожевой таймер задачи отключён
<TaskSettings KindOfTask="Cyclic" Interval="t#10ms">
<Watchdog Enabled="false" /> <!-- на ВСЕХ задачах -->
</TaskSettings>
✓Компилятор: собирается
⚠PLC Lint: поймал
Не баг сам по себе — но для критичного процесса зависший цикл никто не перезапустит. Стоит увидеть в сводке, а не узнать на объекте.