Skip to content

Commit

Permalink
feat(fuzzing, tests, vm, compiler): running the fuzzers locally to fi…
Browse files Browse the repository at this point in the history
…nd a ton more bugs and fixing compiler/macro processor/vm bugs ; includes a pre-computed corpus
  • Loading branch information
SuperFola committed Jun 2, 2024
1 parent 1cd1210 commit 2e4b3ae
Show file tree
Hide file tree
Showing 27 changed files with 188 additions and 12 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
- fixed a bug in the compiler where one could pass a non symbol to `let`, `mut` or `set`, resulting in a compiler crash
- fixed a bug in the macro processor where one could pass an unknown symbol to `argcount` and crash the processor
- fixed a bug in the compiler where one could pass something other than a list to `(fun)` as the argument block, resulting in a crash
- fixed a bug in the compiler generating not callable functions
- fixed a bug in the macro processor generating invalid `let` / `mut` / `set` nodes
- fixed a bug in the macro processor allowing out of bounds access with `($ test (@ [1 2 3] -5))`
- fixed a bug in the vm which wrongfully allowed self concat in place: `(concat! lst lst)`
- fixed a bug in the compiler where one could "use" operators without calling them: `(print nil?)`
- fixed a bug in the compiler allowing the use of operators without any argument: `(+)`
- fixed a bug in the vm during error reporting when a non-function was used as a function

### Removed
- removed unused `NodeType::Closure`
Expand Down
2 changes: 1 addition & 1 deletion include/Ark/VM/inline/VM.inl
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ inline void VM::call(internal::ExecutionContext& context, const int16_t argc_)

default:
{
if (m_state.m_symbols.size() > 0)
if (context.last_symbol < m_state.m_symbols.size())
throwVMError(
ErrorKind::Type,
fmt::format(
Expand Down
29 changes: 21 additions & 8 deletions src/arkreactor/Compiler/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,14 @@ namespace Ark
break;
}
}
else
else if (x.nodeType() == NodeType::List)
{
// if we are here, we should have a function name
// push arguments first, then function name, then call it
handleCalls(x, p, is_result_unused, is_terminal, var_name);
}
else
throwCompilerError("boop", x); // FIXME
}

void Compiler::compileSymbol(const Node& x, const int p, const bool is_result_unused)
Expand All @@ -355,8 +357,8 @@ namespace Ark

if (const auto it_builtin = getBuiltin(name))
page(p).emplace_back(Instruction::BUILTIN, static_cast<uint16_t>(it_builtin.value()));
else if (const auto it_operator = getOperator(name))
page(p).emplace_back(static_cast<uint8_t>(FIRST_OPERATOR + it_operator.value()));
else if (getOperator(name).has_value())
throwCompilerError(fmt::format("Found a free standing operator: `{}`", name), x);
else
page(p).emplace_back(LOAD_SYMBOL, addSymbol(x)); // using the variable

Expand Down Expand Up @@ -479,6 +481,9 @@ namespace Ark
if (n != Keyword::Set)
addDefinedSymbol(name);

if (x.constList().size() != 3)
throwCompilerError("Invalid node ; if it was computed by a macro, check that a node is returned", x);

// put value before symbol id
// starting at index = 2 because x is a (let|mut|set variable ...) node
for (std::size_t idx = 2, end = x.constList().size(); idx < end; ++idx)
Expand Down Expand Up @@ -537,8 +542,16 @@ namespace Ark
const int proc_page = -static_cast<int>(m_temp_pages.size());
constexpr std::size_t start_index = 1;

compileExpression(x.constList()[0], proc_page, false, false); // storing proc
// closure chains have been handled: closure.field.field.function
const auto node = x.constList()[0];
const auto maybe_operator = node.nodeType() == NodeType::Symbol ? getOperator(node.string()) : std::nullopt;
if (node.nodeType() == NodeType::Symbol && maybe_operator.has_value())
page(proc_page).emplace_back(static_cast<uint8_t>(FIRST_OPERATOR + maybe_operator.value()));
else
// closure chains have been handled: closure.field.field.function
compileExpression(node, proc_page, false, false); // storing proc

if (m_temp_pages.back().empty())
throwCompilerError(fmt::format("Can not call {}", x.constList()[0].repr()), x);

// it's a builtin/function
if (m_temp_pages.back()[0].opcode < FIRST_OPERATOR)
Expand All @@ -554,7 +567,7 @@ namespace Ark

// jump to the top of the function
page(p).emplace_back(JUMP, 0_u16);
return; // skip the possible Instruction::POP at the end
return; // skip the potential Instruction::POP at the end
}
else
{
Expand Down Expand Up @@ -601,12 +614,12 @@ namespace Ark
page(p).emplace_back(op.opcode, 2); // TODO generalize to n arguments (n >= 2)
}

if (exp_count == 1)
if (exp_count <= 1)
{
if (isUnaryInst(static_cast<Instruction>(op.opcode)))
page(p).emplace_back(op.opcode);
else
throwCompilerError("Operator needs two arguments, but was called with only one", x.constList()[0]);
throwCompilerError(fmt::format("Operator needs two arguments, but was called with {}", exp_count), x.constList()[0]);
}

// need to check we didn't push the (op A B C D...) things for operators not supporting it
Expand Down
7 changes: 4 additions & 3 deletions src/arkreactor/Compiler/Macros/Processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ namespace Ark::internal

void MacroProcessor::registerFuncDef(const Node& node)
{
if (node.nodeType() == NodeType::List && !node.constList().empty() && node.constList()[0].nodeType() == NodeType::Keyword)
if (node.nodeType() == NodeType::List && node.constList().size() == 3 && node.constList()[0].nodeType() == NodeType::Keyword)
{
Keyword kw = node.constList()[0].keyword();
// checking for function definition, which can occur only inside an assignment node
Expand Down Expand Up @@ -331,10 +331,11 @@ namespace Ark::internal
if (num_idx >= 0)
++num_idx;
}
num_idx = num_idx >= 0 ? num_idx : size + num_idx;

if (num_idx < size)
if (num_idx >= 0 && num_idx < size)
return sublist.list()[num_idx];
if (const auto c = size + num_idx; num_idx < 0 && c < size && c >= 0)
return sublist.list()[c];
throwMacroProcessingError(fmt::format("Index ({}) out of range (list size: {})", num_idx, real_size), node);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/arkreactor/VM/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,9 @@ namespace Ark
{
Value* next = popAndResolveAsPtr(context);

if (next == list)
throwVMError(ErrorKind::Mutability, "Can not concat! a list to itself");

if (list->valueType() != ValueType::List || next->valueType() != ValueType::List)
types::generateError(
"concat!",
Expand Down
1 change: 1 addition & 0 deletions tests/errors/capture/can_not_call.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(((begin)))
5 changes: 5 additions & 0 deletions tests/errors/capture/can_not_call.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
At ((begin)) @ 1:12
1 | (((begin)))
| ^~~~~~~~~~~~
2 |
Can not call (begin)
7 changes: 7 additions & 0 deletions tests/errors/compiler/invalid_let.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
($ partial (func ...defargs) {
($ bloc (suffix-dup a (- (argcount func) (len defargs))))
})

(let test_func (fun (a b c) (* a b c)))
(let test_func1 (partial test_func 1))
(test_func1)
9 changes: 9 additions & 0 deletions tests/errors/compiler/invalid_let.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
At (let test_func1) @ 6:1
3 | })
4 |
5 | (let test_func (fun (a b c) (* a b c)))
6 | (let test_func1 (partial test_func 1))
| ^~~~~~~~~~~~~~~~
7 | (test_func1)
8 |
Invalid node ; if it was computed by a macro, check that a node is returned
2 changes: 2 additions & 0 deletions tests/errors/macros/at_out_of_range.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
($ last (...args) (print args " => " (@ args -9)))
(last 1 5 6 7 8)
6 changes: 6 additions & 0 deletions tests/errors/macros/at_out_of_range.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
At (@ (list 1 5 6 7 8) -9) @ 1:49
1 | ($ last (...args) (print args " => " (@ args -9)))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 | (last 1 5 6 7 8)
3 |
Index (-9) out of range (list size: 5)
2 changes: 2 additions & 0 deletions tests/errors/mutability/self_concat.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(mut d [4 5 6])
(concat! d d)
3 changes: 3 additions & 0 deletions tests/errors/mutability/self_concat.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MutabilityError: Can not concat! a list to itself

At IP: 8, PP: 0, SP: 0
2 changes: 2 additions & 0 deletions tests/errors/operators/freestanding.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let ba0 (fun (a b) ()))
(ba0 0 0 nil?)
6 changes: 6 additions & 0 deletions tests/errors/operators/freestanding.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
At nil? @ 2:15
1 | (let ba0 (fun (a b) ()))
2 | (ba0 0 0 nil?)
| ^~~~~~~~~~~~~~
3 |
Found a free standing operator: `nil?`
1 change: 1 addition & 0 deletions tests/errors/operators/no_args.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
((+))
5 changes: 5 additions & 0 deletions tests/errors/operators/no_args.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
At + @ 1:4
1 | ((+))
| ^
2 |
Operator needs two arguments, but was called with 0
2 changes: 2 additions & 0 deletions tests/errors/type/nil_not_a_function.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(())
(fun (a b) (if 1 2 3))
3 changes: 3 additions & 0 deletions tests/errors/type/nil_not_a_function.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TypeError: nil is not a Function but a Nil

At IP: 2, PP: 0, SP: 0
81 changes: 81 additions & 0 deletions tests/fuzzing/arkscript.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"let"
"mut"
"set"
"del"
"fun"
"if"
"while"
"begin"
"import"

"("
")"
"{"
"}"
"["
"]"

"len"
"empty?"
"tail"
"head"
"nil?"
"assert"
"toNumber"
"toString"
"and"
"or"
"mod"
"type"
"hasField"
"not"
"true"
"false"
"nil"
"math:pi"
"math:e"
"math:tau"
"math:Inf"
"math:NaN"
"append"
"concat"
"list"
"append!"
"concat!"
"pop"
"pop!"
"list:reverse"
"list:find"
"list:slice"
"list:sort"
"list:fill"
"list:setAt"
"print"
"puts"
"input"
"io:writeFile"
"io:readFile"
"io:fileExists?"
"io:listFiles"
"io:dir?"
"io:makeDir"
"io:removeFiles"
"time"
"sys:exec"
"sys:sleep"
"str:format"
"str:find"
"str:removeAt"
"math:exp"
"math:ln"
"math:ceil"
"math:floor"
"math:round"
"math:NaN?"
"math:Inf?"
"math:cos"
"math:sin"
"math:tan"
"math:arccos"
"math:arcsin"
"math:arctan"
1 change: 1 addition & 0 deletions tests/fuzzing/corpus/can_not_call.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(((begin)))
7 changes: 7 additions & 0 deletions tests/fuzzing/corpus/invalid_let.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
($ partial (func ...defargs) {
($ bloc (suffix-dup a (- (argcount func) (len defargs))))
})

(let test_func (fun (a b c) (* a b c)))
(let test_func1 (partial test_func 1))
(test_func1)
2 changes: 2 additions & 0 deletions tests/fuzzing/corpus/macro_at_out_of_range.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
($ last (...args) (print args " => " (@ args -9)))
(last 1 5 6 7 8)
2 changes: 2 additions & 0 deletions tests/fuzzing/corpus/nil_not_a_function.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(())
(fun (a b) (if 1 2 3))
2 changes: 2 additions & 0 deletions tests/fuzzing/corpus/ope_freestanding.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let ba0 (fun (a b) ()))
(ba0 0 0 nil?)
1 change: 1 addition & 0 deletions tests/fuzzing/corpus/ope_no_args.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
((+))
2 changes: 2 additions & 0 deletions tests/fuzzing/corpus/self_concat.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(mut d [4 5 6])
(concat! d d)

0 comments on commit 2e4b3ae

Please sign in to comment.