Первая версия теста технически была относительно простой: грамматика Lua 5.1 описана в формате Protobuf и с помощью библиотеки
libprotobuf-mutator генерировались случайные структуры в формате Protobuf, которые сериализовались в программы на Lua и исполнялись в LuaJIT. Такой тест позволил нам тестировать LuaJIT с помощью синтаксически (почти, об этом ниже) корректных программ. Однако у этой версии теста была проблема: программы часто содержали зацикливания из-за рекурсивных функций и бесконечных циклов. Из-за этого тест часто зависал и тестирование завершалось по таймауту. Нужно было придумать как избегать таких проблем. Тут важно сказать, что так как мы тестируем JIT-компилятор, то функции и циклы в сгенерированных программах нам нужны чтобы включать компиляцию горячих участков кода, мы не можем убрать их из грамматики. То есть задача была такой: использовать функции с ограничением по количеству запусков и циклы с ограничением по количеству итераций. Решение заимствовали из статьи "Program Reconditioning: Avoiding Undefined Behaviour When Finding and Reducing Compiler Bugs" - в каждый цикл и функцию добавили счетчик и выполнение тела функции и цикла прекращается по достижении некоторого значения.-- Было:
while (true) do
foo = 'bar'
...
end
-- Стало:
counter_0 = 0
while (true) do
if counter_0 > 5 then
break
end
...
end
Такой же способ используется в фаззере Fuzzili для Javasript. За поиск решения этой проблемы спасибо моему коллеге Сергею К. (Серега, твоя секунда славы), а за реализацию Римме Т. (Римма, твоя секунды славы). Так мы избавились от зацикливаний в программах и нашли после этого еще несколько багов в LuaJIT.