Skip to content

Commit

Permalink
test/fuzz: refactor LuaJIT fuzzer
Browse files Browse the repository at this point in the history
This refactoring will:

1. Move macros from a header to the source file.
Macros should be used in header only with undef to avoid redefinitions.
Undef directive is not useful since we want to use these macros in the
source file.

2. Remove `using namespace lua_grammar` from header.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rs-using-directive

3. Moving serializer entry point and constant parameters into
luajit_fuzzer namespace.
It's a common practice in C++ to avoid name collisions.

4. Move serializer functions into anonymous namespace.
These functions are not a part of the interface so should have
static linkage.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rs-unnamed2

5. Fix ConvertToStringDefault function.
It was logically wrong so it would generate an identifier `123` from
`*123`.

NO_CHANGELOG=internal
NO_DOC=fuzzer fix
  • Loading branch information
rtolkacheva authored and igormunkin committed Jul 14, 2023
1 parent 4d004bb commit 56488e1
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 140 deletions.
2 changes: 1 addition & 1 deletion test/fuzz/luaL_loadbuffer/luaL_loadbuffer_fuzzer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ DEFINE_PROTO_FUZZER(const lua_grammar::Block &message)
if (!L)
return;

std::string code = MainBlockToString(message);
std::string code = luajit_fuzzer::MainBlockToString(message);

if (::getenv("LPM_DUMP_NATIVE_INPUT") && code.size() != 0) {
std::cout << "-------------------------" << std::endl;
Expand Down
176 changes: 135 additions & 41 deletions test/fuzz/luaL_loadbuffer/serializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,109 @@
#include <stack>
#include <string>

using namespace lua_grammar;

#define PROTO_TOSTRING(TYPE, VAR_NAME) \
std::string TYPE##ToString(const TYPE & (VAR_NAME))

/* PROTO_TOSTRING version for nested (depth=2) protobuf messages. */
#define NESTED_PROTO_TOSTRING(TYPE, VAR_NAME, PARENT_MESSAGE) \
std::string TYPE##ToString \
(const PARENT_MESSAGE::TYPE & (VAR_NAME))

namespace luajit_fuzzer {
namespace {

const std::string kCounterNamePrefix = "counter_";

PROTO_TOSTRING(Block, block);
PROTO_TOSTRING(Chunk, chunk);

PROTO_TOSTRING(Statement, stat);

/** LastStatement and nested types. */
PROTO_TOSTRING(LastStatement, laststat);
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement);

/**
* Statement options.
*/

/** AssignmentList and nested types. */
PROTO_TOSTRING(AssignmentList, assignmentlist);
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList);

/** FunctionCall and nested types. */
PROTO_TOSTRING(FunctionCall, call);
NESTED_PROTO_TOSTRING(Args, args, FunctionCall);
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall);
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall);

/** DoBlock, WhileCycle and RepeatCycle clauses. */
PROTO_TOSTRING(DoBlock, block);
PROTO_TOSTRING(WhileCycle, whilecycle);
PROTO_TOSTRING(RepeatCycle, repeatcycle);

/** IfStatement and nested types. */
PROTO_TOSTRING(IfStatement, statement);
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement);

/** ForCycleName and ForCycleList clauses. */
PROTO_TOSTRING(ForCycleName, forcyclename);
PROTO_TOSTRING(ForCycleList, forcyclelist);

/** Function and nested types. */
PROTO_TOSTRING(Function, func);
NESTED_PROTO_TOSTRING(FuncName, funcname, Function);

PROTO_TOSTRING(NameList, namelist);
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody);
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody);

/** LocalFunc and LocalNames clauses. */
PROTO_TOSTRING(LocalFunc, localfunc);
PROTO_TOSTRING(LocalNames, localnames);

/**
* Expressions and variables.
*/

/** Expressions clauses. */
PROTO_TOSTRING(ExpressionList, explist);
PROTO_TOSTRING(OptionalExpressionList, explist);
PROTO_TOSTRING(PrefixExpression, prefExpr);

/* Variable and nested types. */
PROTO_TOSTRING(Variable, var);
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable);
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable);

/** Expression and nested types. */
PROTO_TOSTRING(Expression, expr);
NESTED_PROTO_TOSTRING(AnonFunc, function, Expression);
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression);
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression);

/**
* Tables and fields.
*/
PROTO_TOSTRING(TableConstructor, table);
PROTO_TOSTRING(FieldList, fieldlist);
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList);

/** Field and nested types. */
PROTO_TOSTRING(Field, field);
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field);
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field);
PROTO_TOSTRING(FieldSep, sep);

/** Operators. */
PROTO_TOSTRING(BinaryOperator, op);
PROTO_TOSTRING(UnaryOperator, op);

/** Identifier (Name). */
PROTO_TOSTRING(Name, name);

/**
* Class that controls id creation for counters. Basically, a
* variable wrapper that guarantees variable to be incremented.
Expand Down Expand Up @@ -137,69 +236,43 @@ FuncBodyToStringReqProtected(const FuncBody &body,
return body_str;
}

} /* namespace */

std::string
MainBlockToString(const Block &block)
{
GetCounterIdProvider().clean();

std::string block_str = BlockToString(block);
std::string retval;

for (size_t i = 0; i < GetCounterIdProvider().count(); ++i) {
retval += GetCounterName(i);
retval += " = 0\n";
}
retval += block_str;

return retval;
}

static inline std::string
RemoveLeadingNumbers(const std::string &s)
{
for (size_t i = 0; i < s.length(); ++i)
if (!std::isdigit(s[i]))
return s.substr(i);
return "";
}

static inline std::string
ClearNonIdentifierSymbols(const std::string &s)
ClearIdentifier(const std::string &identifier)
{
std::string cleared;

if (std::isalpha(s[0]) || s[0] == '_')
cleared += s[0];

for (size_t i = 1; i < s.length(); ++i)
if (std::iswalnum(s[i]) || s[i] == '_')
cleared += s[i];

bool has_first_not_digit = false;
for (char c : identifier) {
if (has_first_not_digit && (std::iswalnum(c) || c == '_')) {
cleared += c;
} else if (std::isalpha(c) || c == '_') {
has_first_not_digit = true;
cleared += c;
}
}
return cleared;
}

static inline std::string
inline std::string
clamp(std::string s, size_t maxSize = kMaxStrLength)
{
if (s.size() > maxSize)
s.resize(maxSize);
return s;
}

static inline double
inline double
clamp(double number, double upper, double lower)
{
return number <= lower ? lower :
number >= upper ? upper : number;
}

static inline std::string
inline std::string
ConvertToStringDefault(const std::string &s)
{
std::string ident = RemoveLeadingNumbers(s);
ident = clamp(ClearNonIdentifierSymbols(ident));
std::string ident = ClearIdentifier(s);
ident = clamp(ident);
if (ident.empty())
return std::string(kDefaultIdent);
return ident;
Expand Down Expand Up @@ -885,3 +958,24 @@ PROTO_TOSTRING(Name, name)
std::string ident = ConvertToStringDefault(name.name());
return ident + std::to_string(name.num() % kMaxIdentifiers);
}

} /* namespace */

std::string
MainBlockToString(const Block &block)
{
GetCounterIdProvider().clean();

std::string block_str = BlockToString(block);
std::string retval;

for (size_t i = 0; i < GetCounterIdProvider().count(); ++i) {
retval += GetCounterName(i);
retval += " = 0\n";
}
retval += block_str;

return retval;
}

} /* namespace luajit_fuzzer */
103 changes: 5 additions & 98 deletions test/fuzz/luaL_loadbuffer/serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@
*/
#pragma once

#include "lua_grammar.pb.h"

using namespace lua_grammar;
#include <string>

#define PROTO_TOSTRING(TYPE, VAR_NAME) \
std::string TYPE##ToString(const TYPE & (VAR_NAME))
#include "lua_grammar.pb.h"

/* PROTO_TOSTRING version for nested (depth=2) protobuf messages. */
#define NESTED_PROTO_TOSTRING(TYPE, VAR_NAME, PARENT_MESSAGE) \
std::string TYPE##ToString \
(const PARENT_MESSAGE::TYPE & (VAR_NAME))
namespace luajit_fuzzer {

/**
* Fuzzing parameters:
Expand Down Expand Up @@ -47,93 +41,6 @@ constexpr char kDefaultIdent[] = "Name";
* recursions.
*/
std::string
MainBlockToString(const Block &block);

PROTO_TOSTRING(Block, block);
PROTO_TOSTRING(Chunk, chunk);

PROTO_TOSTRING(Statement, stat);

/** LastStatement and nested types. */
PROTO_TOSTRING(LastStatement, laststat);
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement);

/**
* Statement options.
*/

/** AssignmentList and nested types. */
PROTO_TOSTRING(AssignmentList, assignmentlist);
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList);

/** FunctionCall and nested types. */
PROTO_TOSTRING(FunctionCall, call);
NESTED_PROTO_TOSTRING(Args, args, FunctionCall);
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall);
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall);

/** DoBlock, WhileCycle and RepeatCycle clauses. */
PROTO_TOSTRING(DoBlock, block);
PROTO_TOSTRING(WhileCycle, whilecycle);
PROTO_TOSTRING(RepeatCycle, repeatcycle);

/** IfStatement and nested types. */
PROTO_TOSTRING(IfStatement, statement);
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement);

/** ForCycleName and ForCycleList clauses. */
PROTO_TOSTRING(ForCycleName, forcyclename);
PROTO_TOSTRING(ForCycleList, forcyclelist);

/** Function and nested types. */
PROTO_TOSTRING(Function, func);
NESTED_PROTO_TOSTRING(FuncName, funcname, Function);

PROTO_TOSTRING(NameList, namelist);
PROTO_TOSTRING(FuncBody, body);
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody);
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody);

/** LocalFunc and LocalNames clauses. */
PROTO_TOSTRING(LocalFunc, localfunc);
PROTO_TOSTRING(LocalNames, localnames);

/**
* Expressions and variables.
*/

/** Expressions clauses. */
PROTO_TOSTRING(ExpressionList, explist);
PROTO_TOSTRING(OptionalExpressionList, explist);
PROTO_TOSTRING(PrefixExpression, prefExpr);

/* Variable and nested types. */
PROTO_TOSTRING(Variable, var);
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable);
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable);

/** Expression and nested types. */
PROTO_TOSTRING(Expression, expr);
NESTED_PROTO_TOSTRING(AnonFunc, function, Expression);
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression);
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression);

/**
* Tables and fields.
*/
PROTO_TOSTRING(TableConstructor, table);
PROTO_TOSTRING(FieldList, fieldlist);
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList);

/** Field and nested types. */
PROTO_TOSTRING(Field, field);
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field);
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field);
PROTO_TOSTRING(FieldSep, sep);

/** Operators. */
PROTO_TOSTRING(BinaryOperator, op);
PROTO_TOSTRING(UnaryOperator, op);
MainBlockToString(const lua_grammar::Block &block);

/** Identifier (Name). */
PROTO_TOSTRING(Name, name);
} /* namespace luajit_fuzzer */

0 comments on commit 56488e1

Please sign in to comment.