Coverage Report

Created: 2024-04-23 06:32

/src/testdir/tests/capi/luaL_loadbuffer_proto/serializer.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: BSD-2-Clause
3
 *
4
 * Copyright 2022, Tarantool AUTHORS, please see AUTHORS file.
5
 */
6
#include "serializer.h"
7
8
#include <stack>
9
#include <string>
10
11
/**
12
* If control flow reaches the point of the unreachable(), the program is
13
* undefined. It is useful in situations where the compiler cannot deduce
14
* the unreachability of the code.
15
*/
16
#if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
17
0
#  define unreachable() (assert(0), __builtin_unreachable())
18
#else
19
#  define unreachable() (assert(0))
20
#endif
21
22
using namespace lua_grammar;
23
24
extern char preamble_lua[];
25
26
#define PROTO_TOSTRING(TYPE, VAR_NAME) \
27
  std::string TYPE##ToString(const TYPE & (VAR_NAME))
28
29
/* PROTO_TOSTRING version for nested (depth=2) protobuf messages. */
30
#define NESTED_PROTO_TOSTRING(TYPE, VAR_NAME, PARENT_MESSAGE) \
31
  std::string TYPE##ToString \
32
  (const PARENT_MESSAGE::TYPE & (VAR_NAME))
33
34
namespace luajit_fuzzer {
35
namespace {
36
37
/*
38
 * The following keywords are reserved and cannot be used as names,
39
 * see Lua 5.1 Reference Manual, 2.1 – Lexical Conventions.
40
 */
41
const std::set<std::string> KReservedLuaKeywords {
42
  "and",
43
  "break",
44
  "do",
45
  "else",
46
  "elseif",
47
  "end",
48
  "false",
49
  "for",
50
  "function",
51
  "if",
52
  "in",
53
  "local",
54
  "nil",
55
  "not",
56
  "or",
57
  "repeat",
58
  "return",
59
  "then",
60
  "true",
61
  "until",
62
  "while",
63
};
64
65
const std::string kCounterNamePrefix = "counter_";
66
const std::string kNumberWrapperName = "always_number";
67
const std::string kBinOpWrapperName = "only_numbers_cmp";
68
const std::string kNotNaNAndNilWrapperName = "not_nan_and_nil";
69
70
PROTO_TOSTRING(Block, block);
71
PROTO_TOSTRING(Chunk, chunk);
72
73
PROTO_TOSTRING(Statement, stat);
74
75
/** LastStatement and nested types. */
76
PROTO_TOSTRING(LastStatement, laststat);
77
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement);
78
79
/**
80
 * Statement options.
81
 */
82
83
/** AssignmentList and nested types. */
84
PROTO_TOSTRING(AssignmentList, assignmentlist);
85
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList);
86
87
/** FunctionCall and nested types. */
88
PROTO_TOSTRING(FunctionCall, call);
89
NESTED_PROTO_TOSTRING(Args, args, FunctionCall);
90
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall);
91
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall);
92
93
/** DoBlock, WhileCycle and RepeatCycle clauses. */
94
PROTO_TOSTRING(DoBlock, block);
95
PROTO_TOSTRING(WhileCycle, whilecycle);
96
PROTO_TOSTRING(RepeatCycle, repeatcycle);
97
98
/** IfStatement and nested types. */
99
PROTO_TOSTRING(IfStatement, statement);
100
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement);
101
102
/** ForCycleName and ForCycleList clauses. */
103
PROTO_TOSTRING(ForCycleName, forcyclename);
104
PROTO_TOSTRING(ForCycleList, forcyclelist);
105
106
/** Function and nested types. */
107
PROTO_TOSTRING(Function, func);
108
NESTED_PROTO_TOSTRING(FuncName, funcname, Function);
109
110
PROTO_TOSTRING(NameList, namelist);
111
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody);
112
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody);
113
114
/** LocalFunc and LocalNames clauses. */
115
PROTO_TOSTRING(LocalFunc, localfunc);
116
PROTO_TOSTRING(LocalNames, localnames);
117
118
/**
119
 * Expressions and variables.
120
 */
121
122
/** Expressions clauses. */
123
PROTO_TOSTRING(ExpressionList, explist);
124
PROTO_TOSTRING(OptionalExpressionList, explist);
125
PROTO_TOSTRING(PrefixExpression, prefExpr);
126
127
/* Variable and nested types. */
128
PROTO_TOSTRING(Variable, var);
129
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable);
130
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable);
131
132
/** Expression and nested types. */
133
PROTO_TOSTRING(Expression, expr);
134
NESTED_PROTO_TOSTRING(AnonFunc, function, Expression);
135
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression);
136
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression);
137
138
/**
139
 * Tables and fields.
140
 */
141
PROTO_TOSTRING(TableConstructor, table);
142
PROTO_TOSTRING(FieldList, fieldlist);
143
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList);
144
145
/** Field and nested types. */
146
PROTO_TOSTRING(Field, field);
147
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field);
148
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field);
149
PROTO_TOSTRING(FieldSep, sep);
150
151
/** Operators. */
152
PROTO_TOSTRING(BinaryOperator, op);
153
PROTO_TOSTRING(UnaryOperator, op);
154
155
/** Identifier (Name). */
156
PROTO_TOSTRING(Name, name);
157
158
std::string
159
NumberWrappedExpressionToString(const Expression &expr)
160
8.59k
{
161
8.59k
  std::string retval;
162
8.59k
  retval += kNumberWrapperName;
163
8.59k
  retval += "(";
164
8.59k
  retval += ExpressionToString(expr);
165
8.59k
  retval += ")";
166
167
8.59k
  return retval;
168
8.59k
}
169
170
std::string
171
AllowedIndexExpressionToString(const Expression &expr)
172
2.86k
{
173
2.86k
  std::string retval;
174
2.86k
  retval += kNotNaNAndNilWrapperName;
175
2.86k
  retval += "(";
176
2.86k
  retval += ExpressionToString(expr);
177
2.86k
  retval += ")";
178
2.86k
  return retval;
179
2.86k
}
180
181
/**
182
 * Class that controls id creation for counters. Basically, a
183
 * variable wrapper that guarantees variable to be incremented.
184
 */
185
class CounterIdProvider {
186
public:
187
  /** Returns number of id provided. */
188
  std::size_t count()
189
98.6k
  {
190
98.6k
    return id_;
191
98.6k
  }
192
193
  /** Returns a new id that was not used after last clean(). */
194
  std::size_t next()
195
96.6k
  {
196
96.6k
    return id_++;
197
96.6k
  }
198
199
  /**
200
   * Cleans history. Should be used to make fuzzer starts
201
   * independent.
202
   */
203
  void clean()
204
2.05k
  {
205
2.05k
    id_ = 0;
206
2.05k
  }
207
208
private:
209
  std::size_t id_ = 0;
210
};
211
212
/** A singleton for counter id provider. */
213
CounterIdProvider&
214
GetCounterIdProvider()
215
197k
{
216
197k
  static CounterIdProvider provider;
217
197k
  return provider;
218
197k
}
219
220
std::string
221
GetCounterName(std::size_t id)
222
193k
{
223
193k
  return kCounterNamePrefix + std::to_string(id);
224
193k
}
225
226
/** Returns `<counter_name> = <counter_name> + 1`. */
227
std::string
228
GetCounterIncrement(const std::string &counter_name)
229
96.6k
{
230
96.6k
  std::string retval = counter_name;
231
96.6k
  retval += " = ";
232
96.6k
  retval += counter_name;
233
96.6k
  retval += " + 1\n";
234
96.6k
  return retval;
235
96.6k
}
236
237
/**
238
 * Returns `if <counter_name> > kMaxCounterValue then
239
 * <then_block> end`.
240
 */
241
std::string
242
GetCondition(const std::string &counter_name, const std::string &then_block)
243
96.6k
{
244
96.6k
  std::string retval = "if ";
245
96.6k
  retval += counter_name;
246
96.6k
  retval += " > ";
247
96.6k
  retval += std::to_string(kMaxCounterValue);
248
96.6k
  retval += " then ";
249
96.6k
  retval += then_block;
250
96.6k
  retval += " end\n";
251
96.6k
  return retval;
252
96.6k
}
253
254
/**
255
 * Class that registers and provides context during code
256
 * generation.
257
 * Used to generate correct Lua code.
258
 */
259
class Context {
260
public:
261
  enum class BlockType {
262
    kReturnable,
263
    kBreakable,
264
    kReturnableWithVararg,
265
  };
266
267
  void step_in(BlockType type)
268
96.6k
  {
269
96.6k
    block_stack_.push(type);
270
96.6k
    if (block_type_is_returnable_(type)) {
271
44.3k
      returnable_stack_.push(type);
272
44.3k
    }
273
96.6k
  }
274
275
  void step_out()
276
96.6k
  {
277
96.6k
    assert(!block_stack_.empty());
278
96.6k
    if (block_type_is_returnable_(block_stack_.top())) {
279
44.3k
      assert(!returnable_stack_.empty());
280
0
      returnable_stack_.pop();
281
44.3k
    }
282
0
    block_stack_.pop();
283
96.6k
  }
284
285
  std::string get_next_block_setup()
286
96.6k
  {
287
96.6k
    std::size_t id = GetCounterIdProvider().next();
288
96.6k
    std::string counter_name = GetCounterName(id);
289
290
96.6k
    return GetCondition(counter_name, get_exit_statement_()) +
291
96.6k
           GetCounterIncrement(counter_name);
292
96.6k
  }
293
294
  bool break_is_possible()
295
3.25k
  {
296
3.25k
    return !block_stack_.empty() &&
297
3.25k
           block_stack_.top() == BlockType::kBreakable;
298
3.25k
  }
299
300
  bool return_is_possible()
301
7.33k
  {
302
7.33k
    return !returnable_stack_.empty();
303
7.33k
  }
304
305
  bool vararg_is_possible()
306
3.30k
  {
307
3.30k
    return (returnable_stack_.empty() ||
308
3.30k
      (!returnable_stack_.empty() &&
309
521
       returnable_stack_.top() ==
310
521
        BlockType::kReturnableWithVararg));
311
3.30k
  }
312
313
private:
314
315
  bool block_type_is_returnable_(BlockType type)
316
193k
  {
317
193k
    switch (type) {
318
104k
    case BlockType::kBreakable:
319
104k
      return false;
320
84.5k
    case BlockType::kReturnable:
321
88.6k
    case BlockType::kReturnableWithVararg:
322
88.6k
      return true;
323
193k
    }
324
193k
    unreachable();
325
193k
  }
326
327
  std::string get_exit_statement_()
328
96.6k
  {
329
96.6k
    assert(!block_stack_.empty());
330
0
    switch (block_stack_.top()) {
331
52.2k
    case BlockType::kBreakable:
332
52.2k
      return "break";
333
42.2k
    case BlockType::kReturnable:
334
44.3k
    case BlockType::kReturnableWithVararg:
335
44.3k
      return "return";
336
96.6k
    }
337
96.6k
    unreachable();
338
96.6k
  }
339
340
  std::stack<BlockType> block_stack_;
341
  /*
342
   * The returnable block can be exited with return from
343
   * the breakable block within it, but the breakable block
344
   * cannot be exited with break from the returnable block within
345
   * it.
346
   * Valid code:
347
   * `function foo() while true do return end end`
348
   * Erroneous code:
349
   * `while true do function foo() break end end`
350
   * This stack is used to check if `return` is possible.
351
   */
352
  std::stack<BlockType> returnable_stack_;
353
};
354
355
Context&
356
GetContext()
357
303k
{
358
303k
  static Context context;
359
303k
  return context;
360
303k
}
361
362
/**
363
 * Block may be placed not only in a cycle, so specially for cycles
364
 * there is a function that will add a break condition and a
365
 * counter increment.
366
 */
367
std::string
368
BlockToStringCycleProtected(const Block &block)
369
52.2k
{
370
52.2k
  std::string retval = GetContext().get_next_block_setup();
371
52.2k
  retval += ChunkToString(block.chunk());
372
52.2k
  return retval;
373
52.2k
}
374
375
/**
376
 * DoBlock may be placed not only in a cycle, so specially for
377
 * cycles there is a function that will call
378
 * BlockToStringCycleProtected().
379
 */
380
std::string
381
DoBlockToStringCycleProtected(const DoBlock &block)
382
20.6k
{
383
20.6k
  std::string retval = "do\n";
384
20.6k
  retval += BlockToStringCycleProtected(block.block());
385
20.6k
  retval += "end\n";
386
20.6k
  return retval;
387
20.6k
}
388
389
/**
390
 * FuncBody may contain recursive calls, so for all function bodies,
391
 * there is a function that adds a return condition and a counter
392
 * increment.
393
 */
394
std::string
395
FuncBodyToStringReqProtected(const FuncBody &body)
396
44.3k
{
397
44.3k
  std::string body_str = "( ";
398
44.3k
  if (body.has_parlist()) {
399
5.83k
    body_str += ParListToString(body.parlist());
400
5.83k
  }
401
44.3k
  body_str += " )\n\t";
402
403
44.3k
  body_str += GetContext().get_next_block_setup();
404
405
44.3k
  body_str += BlockToString(body.block());
406
44.3k
  body_str += "end\n";
407
44.3k
  return body_str;
408
44.3k
}
409
410
bool
411
FuncBodyHasVararg(const FuncBody &body)
412
44.3k
{
413
44.3k
  if (!body.has_parlist()) {
414
38.5k
    return false;
415
38.5k
  }
416
5.83k
  const FuncBody::ParList &parlist = body.parlist();
417
5.83k
  switch (parlist.parlist_oneof_case()) {
418
933
  case FuncBody::ParList::ParlistOneofCase::kNamelist:
419
933
    return parlist.namelist().has_ellipsis();
420
1.49k
  case FuncBody::ParList::ParlistOneofCase::kEllipsis:
421
1.49k
    return true;
422
3.40k
  default:
423
3.40k
    return parlist.namelist().has_ellipsis();
424
5.83k
  }
425
5.83k
}
426
427
Context::BlockType
428
GetFuncBodyType(const FuncBody &body)
429
44.3k
{
430
44.3k
  return FuncBodyHasVararg(body) ?
431
2.08k
    Context::BlockType::kReturnableWithVararg :
432
44.3k
    Context::BlockType::kReturnable;
433
44.3k
}
434
435
std::string
436
ClearIdentifier(const std::string &identifier)
437
437k
{
438
437k
  std::string cleared;
439
440
437k
  bool has_first_not_digit = false;
441
437k
  for (char c : identifier) {
442
347k
    if (has_first_not_digit && (std::iswalnum(c) || c == '_')) {
443
99.1k
      cleared += c;
444
248k
    } else if (std::isalpha(c) || c == '_') {
445
8.26k
      has_first_not_digit = true;
446
8.26k
      cleared += c;
447
8.26k
    }
448
347k
  }
449
437k
  return cleared;
450
437k
}
451
452
inline std::string
453
clamp(std::string s, size_t maxSize = kMaxStrLength)
454
437k
{
455
437k
  if (s.size() > maxSize)
456
1.25k
    s.resize(maxSize);
457
437k
  return s;
458
437k
}
459
460
inline double
461
clamp(double number, double upper, double lower)
462
13.0k
{
463
13.0k
  return number <= lower ? lower :
464
13.0k
         number >= upper ? upper : number;
465
13.0k
}
466
467
inline std::string
468
ConvertToStringDefault(const std::string &s)
469
437k
{
470
437k
  std::string ident = ClearIdentifier(s);
471
437k
  ident = clamp(ident);
472
437k
  if (ident.empty())
473
428k
    return std::string(kDefaultIdent);
474
8.26k
  return ident;
475
437k
}
476
477
PROTO_TOSTRING(Block, block)
478
58.4k
{
479
58.4k
  return ChunkToString(block.chunk());
480
58.4k
}
481
482
PROTO_TOSTRING(Chunk, chunk)
483
110k
{
484
110k
  std::string chunk_str;
485
310k
  for (int i = 0; i < chunk.stat_size(); ++i)
486
199k
    chunk_str += StatementToString(chunk.stat(i)) + "\n";
487
488
110k
  if (chunk.has_laststat())
489
10.5k
    chunk_str += LastStatementToString(chunk.laststat()) + "\n";
490
491
110k
  return chunk_str;
492
110k
}
493
494
/**
495
 * LastStatement and nested types.
496
 */
497
PROTO_TOSTRING(LastStatement, laststat)
498
10.5k
{
499
10.5k
  std::string laststat_str;
500
10.5k
  using LastStatType = LastStatement::LastOneofCase;
501
10.5k
  switch (laststat.last_oneof_case()) {
502
3.43k
  case LastStatType::kExplist:
503
3.43k
    laststat_str = ReturnOptionalExpressionListToString(
504
3.43k
      laststat.explist());
505
3.43k
    break;
506
3.25k
  case LastStatType::kBreak:
507
3.25k
    if (GetContext().break_is_possible()) {
508
2.08k
      laststat_str = "break";
509
2.08k
    }
510
3.25k
    break;
511
3.90k
  default:
512
    /* Chosen as default in order to decrease number of 'break's. */
513
3.90k
    laststat_str = ReturnOptionalExpressionListToString(
514
3.90k
      laststat.explist());
515
3.90k
    break;
516
10.5k
  }
517
518
  /*
519
   * Add a semicolon when last statement is not empty
520
   * to avoid errors like:
521
   *
522
   * <preamble.lua>
523
   * (nil):Name0()
524
   * (nil)() -- ambiguous syntax (function call x new statement) near '('
525
   */
526
10.5k
  if (!laststat_str.empty())
527
7.05k
    laststat_str += "; ";
528
529
10.5k
  return laststat_str;
530
10.5k
}
531
532
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement)
533
7.33k
{
534
7.33k
  if (!GetContext().return_is_possible()) {
535
2.37k
    return "";
536
2.37k
  }
537
538
4.96k
  std::string explist_str = "return";
539
4.96k
  if (explist.has_explist()) {
540
2.69k
    explist_str += " " + ExpressionListToString(explist.explist());
541
2.69k
    explist_str += " ";
542
2.69k
  }
543
4.96k
  return explist_str;
544
7.33k
}
545
546
/**
547
 * Statement and statement options.
548
 */
549
PROTO_TOSTRING(Statement, stat)
550
199k
{
551
199k
  std::string stat_str;
552
199k
  using StatType = Statement::StatOneofCase;
553
199k
  switch (stat.stat_oneof_case()) {
554
8.73k
  case StatType::kList:
555
8.73k
    stat_str = AssignmentListToString(stat.list());
556
8.73k
    break;
557
78.9k
  case StatType::kCall:
558
78.9k
    stat_str = FunctionCallToString(stat.call());
559
78.9k
    break;
560
2.18k
  case StatType::kBlock:
561
2.18k
    stat_str = DoBlockToString(stat.block());
562
2.18k
    break;
563
4.04k
  case StatType::kWhilecycle:
564
4.04k
    stat_str = WhileCycleToString(stat.whilecycle());
565
4.04k
    break;
566
31.5k
  case StatType::kRepeatcycle:
567
31.5k
    stat_str = RepeatCycleToString(stat.repeatcycle());
568
31.5k
    break;
569
5.02k
  case StatType::kIfstat:
570
5.02k
    stat_str = IfStatementToString(stat.ifstat());
571
5.02k
    break;
572
3.51k
  case StatType::kForcyclename:
573
3.51k
    stat_str = ForCycleNameToString(stat.forcyclename());
574
3.51k
    break;
575
13.1k
  case StatType::kForcyclelist:
576
13.1k
    stat_str = ForCycleListToString(stat.forcyclelist());
577
13.1k
    break;
578
5.19k
  case StatType::kFunc:
579
5.19k
    stat_str = FunctionToString(stat.func());
580
5.19k
    break;
581
5.01k
  case StatType::kLocalfunc:
582
5.01k
    stat_str = LocalFuncToString(stat.localfunc());
583
5.01k
    break;
584
5.03k
  case StatType::kLocalnames:
585
5.03k
    stat_str = LocalNamesToString(stat.localnames());
586
5.03k
    break;
587
37.2k
  default:
588
    /**
589
     * Chosen arbitrarily more for simplicity.
590
     * TODO: Choose "more interesting" defaults.
591
     */
592
37.2k
    stat_str = AssignmentListToString(stat.list());
593
37.2k
    break;
594
199k
  }
595
596
  /*
597
   * Always add a semicolon regardless of grammar
598
   * to avoid errors like:
599
   *
600
   * <preamble.lua>
601
   * (nil):Name0()
602
   * (nil)() -- ambiguous syntax (function call x new statement) near '('
603
   */
604
199k
  stat_str += "; ";
605
606
199k
  return stat_str;
607
199k
}
608
609
/**
610
 * AssignmentList and nested types.
611
 */
612
PROTO_TOSTRING(AssignmentList, assignmentlist)
613
45.9k
{
614
45.9k
  std::string list_str = VariableListToString(assignmentlist.varlist());
615
45.9k
  list_str += " = " + ExpressionListToString(assignmentlist.explist());
616
45.9k
  return list_str;
617
45.9k
}
618
619
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList)
620
45.9k
{
621
45.9k
  std::string varlist_str = VariableToString(varlist.var());
622
63.0k
  for (int i = 0; i < varlist.vars_size(); ++i) {
623
17.0k
    varlist_str += ", " + VariableToString(varlist.vars(i));
624
17.0k
    varlist_str += " ";
625
17.0k
  }
626
45.9k
  return varlist_str;
627
45.9k
}
628
629
/**
630
 * FunctionCall and nested types.
631
 */
632
PROTO_TOSTRING(FunctionCall, call)
633
86.2k
{
634
86.2k
  using FuncCallType = FunctionCall::CallOneofCase;
635
86.2k
  switch (call.call_oneof_case()) {
636
4.92k
  case FuncCallType::kPrefArgs:
637
4.92k
    return PrefixArgsToString(call.prefargs());
638
3.90k
  case FuncCallType::kNamedArgs:
639
3.90k
    return PrefixNamedArgsToString(call.namedargs());
640
77.3k
  default:
641
    /* Chosen for more variability of generated programs. */
642
77.3k
    return PrefixNamedArgsToString(call.namedargs());
643
86.2k
  }
644
86.2k
}
645
646
NESTED_PROTO_TOSTRING(Args, args, FunctionCall)
647
86.2k
{
648
86.2k
  using ArgsType = FunctionCall::Args::ArgsOneofCase;
649
86.2k
  switch (args.args_oneof_case()) {
650
1.77k
  case ArgsType::kExplist:
651
1.77k
    return "(" + OptionalExpressionListToString(args.explist()) +
652
1.77k
           ")";
653
742
  case ArgsType::kTableconstructor:
654
742
    return TableConstructorToString(args.tableconstructor());
655
1.52k
  case ArgsType::kStr:
656
1.52k
    return "'" + ConvertToStringDefault(args.str()) + "'";
657
82.1k
  default:
658
    /* For more variability. */
659
82.1k
    return TableConstructorToString(args.tableconstructor());
660
86.2k
  }
661
86.2k
}
662
663
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall)
664
4.92k
{
665
4.92k
  std::string prefixargs_str = PrefixExpressionToString(
666
4.92k
    prefixargs.prefixexp());
667
4.92k
  prefixargs_str += " " + ArgsToString(prefixargs.args());
668
4.92k
  return prefixargs_str;
669
4.92k
}
670
671
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall)
672
81.2k
{
673
81.2k
  std::string predixnamedargs_str = PrefixExpressionToString(
674
81.2k
    prefixnamedargs.prefixexp());
675
81.2k
  predixnamedargs_str += ":" + NameToString(prefixnamedargs.name());
676
81.2k
  predixnamedargs_str += " " + ArgsToString(prefixnamedargs.args());
677
81.2k
  return predixnamedargs_str;
678
81.2k
}
679
680
/**
681
 * DoBlock clause.
682
 */
683
PROTO_TOSTRING(DoBlock, block)
684
2.18k
{
685
2.18k
  return "do\n" + BlockToString(block.block()) + "end\n";
686
2.18k
}
687
688
/**
689
 * WhileCycle clause.
690
 */
691
PROTO_TOSTRING(WhileCycle, whilecycle)
692
4.04k
{
693
4.04k
  GetContext().step_in(Context::BlockType::kBreakable);
694
695
4.04k
  std::string whilecycle_str = "while ";
696
4.04k
  whilecycle_str += ExpressionToString(whilecycle.condition());
697
4.04k
  whilecycle_str += " ";
698
4.04k
  whilecycle_str += DoBlockToStringCycleProtected(whilecycle.doblock());
699
700
4.04k
  GetContext().step_out();
701
4.04k
  return whilecycle_str;
702
4.04k
}
703
704
/**
705
 * RepeatCycle clause.
706
 */
707
PROTO_TOSTRING(RepeatCycle, repeatcycle)
708
31.5k
{
709
31.5k
  GetContext().step_in(Context::BlockType::kBreakable);
710
711
31.5k
  std::string repeatcycle_str = "repeat\n";
712
31.5k
  repeatcycle_str += BlockToStringCycleProtected(repeatcycle.block());
713
31.5k
  repeatcycle_str += "until ";
714
31.5k
  repeatcycle_str += ExpressionToString(repeatcycle.condition());
715
716
31.5k
  GetContext().step_out();
717
31.5k
  return repeatcycle_str;
718
31.5k
}
719
720
/**
721
 * IfStatement and nested types.
722
 */
723
PROTO_TOSTRING(IfStatement, statement)
724
5.02k
{
725
5.02k
  std::string statement_str = "if " +
726
5.02k
    ExpressionToString(statement.condition());
727
5.02k
  statement_str += " then\n\t" + BlockToString(statement.first());
728
729
7.81k
  for (int i = 0; i < statement.clauses_size(); ++i)
730
2.79k
    statement_str += ElseIfBlockToString(statement.clauses(i));
731
732
5.02k
  if (statement.has_last())
733
2.05k
    statement_str += "else\n\t" + BlockToString(statement.last());
734
735
5.02k
  statement_str += "end\n";
736
5.02k
  return statement_str;
737
5.02k
}
738
739
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement)
740
2.79k
{
741
2.79k
  std::string elseifblock_str = "elseif ";
742
2.79k
  elseifblock_str += ExpressionToString(elseifblock.condition());
743
2.79k
  elseifblock_str += " then\n\t";
744
2.79k
  elseifblock_str += BlockToString(elseifblock.block());
745
2.79k
  return elseifblock_str;
746
2.79k
}
747
748
/**
749
 * ForCycleName clause.
750
 * TODO: In 'for i = start, stop, step' construction start, stop, step
751
 * should be numbers. So results of the corresponding expressions
752
 * should be number.
753
 */
754
PROTO_TOSTRING(ForCycleName, forcyclename)
755
3.51k
{
756
3.51k
  GetContext().step_in(Context::BlockType::kBreakable);
757
758
3.51k
  std::string forcyclename_str = "for ";
759
3.51k
  forcyclename_str += NameToString(forcyclename.name());
760
3.51k
  forcyclename_str += " = ";
761
3.51k
  forcyclename_str += NumberWrappedExpressionToString(
762
3.51k
    forcyclename.startexp());
763
3.51k
  forcyclename_str += ", ";
764
3.51k
  forcyclename_str += NumberWrappedExpressionToString(
765
3.51k
    forcyclename.stopexp());
766
767
3.51k
  if (forcyclename.has_stepexp())
768
1.56k
    forcyclename_str += ", " + NumberWrappedExpressionToString(
769
1.56k
      forcyclename.stepexp());
770
771
3.51k
  forcyclename_str += " ";
772
3.51k
  forcyclename_str += DoBlockToStringCycleProtected(
773
3.51k
    forcyclename.doblock());
774
775
3.51k
  GetContext().step_out();
776
3.51k
  return forcyclename_str;
777
3.51k
}
778
779
/**
780
 * ForCycleList clause.
781
 */
782
PROTO_TOSTRING(ForCycleList, forcyclelist)
783
13.1k
{
784
13.1k
  GetContext().step_in(Context::BlockType::kBreakable);
785
786
13.1k
  std::string forcyclelist_str = "for ";
787
13.1k
  forcyclelist_str += NameListToString(forcyclelist.names());
788
13.1k
  forcyclelist_str += " in ";
789
13.1k
  forcyclelist_str += ExpressionListToString(forcyclelist.expressions());
790
13.1k
  forcyclelist_str += " ";
791
13.1k
  forcyclelist_str += DoBlockToStringCycleProtected(
792
13.1k
    forcyclelist.doblock());
793
794
13.1k
  GetContext().step_out();
795
13.1k
  return forcyclelist_str;
796
13.1k
}
797
798
/**
799
 * Function and nested types.
800
 */
801
PROTO_TOSTRING(Function, func)
802
5.19k
{
803
5.19k
  GetContext().step_in(GetFuncBodyType(func.body()));
804
805
5.19k
  std::string func_str = "function ";
806
5.19k
  func_str += FuncNameToString(func.name());
807
5.19k
  func_str += FuncBodyToStringReqProtected(func.body());
808
809
5.19k
  GetContext().step_out();
810
5.19k
  return func_str;
811
5.19k
}
812
813
NESTED_PROTO_TOSTRING(FuncName, funcname, Function)
814
5.19k
{
815
5.19k
  std::string funcname_str = NameToString(funcname.firstname());
816
817
9.26k
  for (int i = 0; i < funcname.names_size(); ++i)
818
4.07k
    funcname_str += "." + NameToString(funcname.names(i));
819
820
5.19k
  if (funcname.has_lastname())
821
615
    funcname_str += ":" + NameToString(funcname.lastname());
822
823
5.19k
  return funcname_str;
824
5.19k
}
825
826
PROTO_TOSTRING(NameList, namelist)
827
22.5k
{
828
22.5k
  std::string namelist_str = NameToString(namelist.firstname());
829
39.6k
  for (int i = 0; i < namelist.names_size(); ++i)
830
17.0k
    namelist_str += ", " + NameToString(namelist.names(i));
831
22.5k
  return namelist_str;
832
22.5k
}
833
834
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody)
835
4.34k
{
836
4.34k
  std::string namelist_str = NameListToString(namelist.namelist());
837
4.34k
  if (namelist.has_ellipsis())
838
589
    namelist_str += ", ...";
839
4.34k
  return namelist_str;
840
4.34k
}
841
842
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody)
843
5.83k
{
844
5.83k
  using ParListType = FuncBody::ParList::ParlistOneofCase;
845
5.83k
  switch (parlist.parlist_oneof_case()) {
846
933
  case ParListType::kNamelist:
847
933
    return NameListWithEllipsisToString(parlist.namelist());
848
1.49k
  case ParListType::kEllipsis:
849
1.49k
    return "...";
850
3.40k
  default:
851
    /* Chosen as default in order to decrease number of ellipses. */
852
3.40k
    return NameListWithEllipsisToString(parlist.namelist());
853
5.83k
  }
854
5.83k
}
855
856
/**
857
 * LocalFunc clause.
858
 */
859
PROTO_TOSTRING(LocalFunc, localfunc)
860
5.01k
{
861
5.01k
  GetContext().step_in(GetFuncBodyType(localfunc.funcbody()));
862
863
5.01k
  std::string localfunc_str = "local function ";
864
5.01k
  localfunc_str += NameToString(localfunc.name());
865
5.01k
  localfunc_str += " ";
866
5.01k
  localfunc_str += FuncBodyToStringReqProtected(localfunc.funcbody());
867
868
5.01k
  GetContext().step_out();
869
5.01k
  return localfunc_str;
870
5.01k
}
871
872
/**
873
 * LocalNames clause.
874
 */
875
PROTO_TOSTRING(LocalNames, localnames)
876
5.03k
{
877
5.03k
  std::string localnames_str = "local ";
878
5.03k
  localnames_str += NameListToString(localnames.namelist());
879
880
5.03k
  if (localnames.has_explist())
881
2.66k
    localnames_str += " = " + ExpressionListToString(
882
2.66k
      localnames.explist());
883
5.03k
  return localnames_str;
884
5.03k
}
885
886
/**
887
 * Expressions and variables.
888
 */
889
890
/**
891
 * Expressions clauses.
892
 */
893
PROTO_TOSTRING(ExpressionList, explist)
894
65.7k
{
895
65.7k
  std::string explist_str;
896
113k
  for (int i = 0; i < explist.expressions_size(); ++i)
897
47.6k
    explist_str += ExpressionToString(explist.expressions(i)) +
898
47.6k
        ", ";
899
65.7k
  explist_str += ExpressionToString(explist.explast()) + " ";
900
65.7k
  return explist_str;
901
65.7k
}
902
903
PROTO_TOSTRING(OptionalExpressionList, explist)
904
1.77k
{
905
1.77k
  if (explist.has_explist())
906
1.32k
    return ExpressionListToString(explist.explist());
907
451
  return "";
908
1.77k
}
909
910
PROTO_TOSTRING(PrefixExpression, prefixexp)
911
105k
{
912
105k
  using PrefExprType = PrefixExpression::PrefixOneofCase;
913
105k
  switch (prefixexp.prefix_oneof_case()) {
914
3.26k
  case PrefExprType::kVar:
915
3.26k
    return VariableToString(prefixexp.var());
916
7.21k
  case PrefExprType::kFunctioncall:
917
7.21k
    return FunctionCallToString(prefixexp.functioncall());
918
4.19k
  case PrefExprType::kExp:
919
4.19k
    return "(" + ExpressionToString(prefixexp.exp()) + ")";
920
91.0k
  default:
921
    /*
922
     * Can be generated too nested expressions with other options,
923
     * though they can be enabled for more variable fuzzing.
924
     */
925
91.0k
    return VariableToString(prefixexp.var());
926
105k
  }
927
105k
}
928
929
/**
930
 * Variable and nested types.
931
 */
932
PROTO_TOSTRING(Variable, var)
933
157k
{
934
157k
  using VarType = Variable::VarOneofCase;
935
157k
  switch (var.var_oneof_case()) {
936
2.03k
  case VarType::kName:
937
2.03k
    return NameToString(var.name());
938
5.98k
  case VarType::kIndexexpr:
939
5.98k
    return IndexWithExpressionToString(var.indexexpr());
940
5.15k
  case VarType::kIndexname:
941
5.15k
    return IndexWithNameToString(var.indexname());
942
144k
  default:
943
    /*
944
     * Can be generated too nested expressions with other options,
945
     * though they can be enabled for more variable fuzzing.
946
     */
947
144k
    return NameToString(var.name());
948
157k
  }
949
157k
}
950
951
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable)
952
5.98k
{
953
5.98k
  std::string indexexpr_str = PrefixExpressionToString(
954
5.98k
    indexexpr.prefixexp());
955
5.98k
  indexexpr_str += "[" + ExpressionToString(indexexpr.exp()) + "]";
956
5.98k
  return indexexpr_str;
957
5.98k
}
958
959
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable)
960
5.15k
{
961
5.15k
  std::string indexname_str = PrefixExpressionToString(
962
5.15k
    indexname.prefixexp());
963
5.15k
  std::string idx_str = ConvertToStringDefault(indexname.name());
964
  /* Prevent using reserved keywords as indices. */
965
5.15k
  if (KReservedLuaKeywords.find(idx_str) != KReservedLuaKeywords.end()) {
966
20
    idx_str += "_1";
967
20
  }
968
5.15k
  indexname_str += "." + idx_str;
969
5.15k
  return indexname_str;
970
5.15k
}
971
972
/**
973
 * Expression and nested types.
974
 */
975
PROTO_TOSTRING(Expression, expr)
976
244k
{
977
244k
  using ExprType = Expression::ExprOneofCase;
978
244k
  switch (expr.expr_oneof_case()) {
979
8.20k
  case ExprType::kNil:
980
8.20k
    return "nil";
981
2.82k
  case ExprType::kFalse:
982
2.82k
    return "false";
983
3.75k
  case ExprType::kTrue:
984
3.75k
    return "true";
985
13.0k
  case ExprType::kNumber: {
986
    /* Clamp number between given boundaries. */
987
13.0k
    double number = clamp(expr.number(), kMaxNumber, kMinNumber);
988
13.0k
    return std::to_string(number);
989
0
  }
990
2.72k
  case ExprType::kStr:
991
2.72k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
992
3.30k
  case ExprType::kEllipsis:
993
3.30k
    if (GetContext().vararg_is_possible()) {
994
2.97k
      return " ... ";
995
2.97k
    } else {
996
334
      return " nil";
997
334
    }
998
34.1k
  case ExprType::kFunction:
999
34.1k
    return AnonFuncToString(expr.function());
1000
8.34k
  case ExprType::kPrefixexp:
1001
8.34k
    return PrefixExpressionToString(expr.prefixexp());
1002
8.06k
  case ExprType::kTableconstructor:
1003
8.06k
    return TableConstructorToString(expr.tableconstructor());
1004
23.8k
  case ExprType::kBinary:
1005
23.8k
    return ExpBinaryOpExpToString(expr.binary());
1006
3.00k
  case ExprType::kUnary:
1007
3.00k
    return UnaryOpExpToString(expr.unary());
1008
133k
  default:
1009
    /**
1010
     * Arbitrary choice.
1011
     * TODO: Choose "more interesting" defaults.
1012
     */
1013
133k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
1014
244k
  }
1015
244k
}
1016
1017
NESTED_PROTO_TOSTRING(AnonFunc, func, Expression)
1018
34.1k
{
1019
34.1k
  GetContext().step_in(GetFuncBodyType(func.body()));
1020
1021
34.1k
  std::string retval = "function ";
1022
34.1k
  retval += FuncBodyToStringReqProtected(func.body());
1023
1024
34.1k
  GetContext().step_out();
1025
34.1k
  return retval;
1026
34.1k
}
1027
1028
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression)
1029
23.8k
{
1030
23.8k
  std::string leftexp_str = ExpressionToString(binary.leftexp());
1031
23.8k
  std::string binop_str = BinaryOperatorToString(binary.binop());
1032
23.8k
  std::string rightexp_str = ExpressionToString(binary.rightexp());
1033
1034
23.8k
  std::string binary_str;
1035
23.8k
  if (binop_str == "<" ||
1036
23.8k
      binop_str == ">" ||
1037
23.8k
      binop_str == "<=" ||
1038
23.8k
      binop_str == ">=") {
1039
2.33k
    binary_str = kBinOpWrapperName;
1040
2.33k
    binary_str += "(" + leftexp_str;
1041
2.33k
    binary_str += ", '" + binop_str + "', ";
1042
2.33k
    binary_str += rightexp_str + ")";
1043
2.33k
    return binary_str;
1044
2.33k
  }
1045
1046
21.5k
  binary_str = leftexp_str;
1047
21.5k
  binary_str += " " + binop_str + " ";
1048
21.5k
  binary_str += rightexp_str;
1049
1050
21.5k
  return binary_str;
1051
23.8k
}
1052
1053
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression)
1054
3.00k
{
1055
3.00k
  std::string unary_str = UnaryOperatorToString(unary.unop());
1056
  /*
1057
   * Add a whitespace before an expression with unary minus,
1058
   * otherwise double hyphen comments the following code
1059
   * and it breaks generated programs syntactically.
1060
   */
1061
3.00k
  unary_str += " " + ExpressionToString(unary.exp());
1062
3.00k
  return unary_str;
1063
3.00k
}
1064
1065
/**
1066
 * Tables and fields.
1067
 */
1068
PROTO_TOSTRING(TableConstructor, table)
1069
90.9k
{
1070
90.9k
  std::string table_str = " (setmetatable({ ";
1071
90.9k
  if (table.has_fieldlist())
1072
6.21k
    table_str += FieldListToString(table.fieldlist());
1073
90.9k
  table_str += " }, table_mt))()";
1074
90.9k
  return table_str;
1075
90.9k
}
1076
1077
PROTO_TOSTRING(FieldList, fieldlist)
1078
6.21k
{
1079
6.21k
  std::string fieldlist_str = FieldToString(fieldlist.firstfield());
1080
15.5k
  for (int i = 0; i < fieldlist.fields_size(); ++i)
1081
9.32k
    fieldlist_str += FieldWithFieldSepToString(fieldlist.fields(i));
1082
6.21k
  if (fieldlist.has_lastsep())
1083
1.65k
    fieldlist_str += FieldSepToString(fieldlist.lastsep());
1084
6.21k
  return fieldlist_str;
1085
6.21k
}
1086
1087
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList)
1088
9.32k
{
1089
9.32k
  std::string field_str = FieldSepToString(field.sep());
1090
9.32k
  field_str += " " + FieldToString(field.field());
1091
9.32k
  return field_str;
1092
9.32k
}
1093
1094
/**
1095
 * Field and nested types.
1096
 */
1097
PROTO_TOSTRING(Field, field)
1098
15.5k
{
1099
15.5k
  using FieldType = Field::FieldOneofCase;
1100
15.5k
  switch (field.field_oneof_case()) {
1101
2.86k
  case FieldType::kExprassign:
1102
2.86k
    return ExpressionAssignmentToString(field.exprassign());
1103
556
  case FieldType::kNamedassign:
1104
556
    return NameAssignmentToString(field.namedassign());
1105
3.77k
  case FieldType::kExpression:
1106
3.77k
    return ExpressionToString(field.expression());
1107
8.34k
  default:
1108
    /* More common case of using fields. */
1109
8.34k
    return NameAssignmentToString(field.namedassign());
1110
15.5k
  }
1111
15.5k
}
1112
1113
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field)
1114
2.86k
{
1115
  /* Prevent error 'table index is nil' and 'table index is NaN'. */
1116
2.86k
  std::string assignment_str = "[ " +
1117
2.86k
    AllowedIndexExpressionToString(assignment.key()) + " ]";
1118
2.86k
  assignment_str += " = " + ExpressionToString(assignment.value());
1119
2.86k
  return assignment_str;
1120
2.86k
}
1121
1122
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field)
1123
8.90k
{
1124
8.90k
  std::string assignment_str = NameToString(assignment.name());
1125
8.90k
  assignment_str += " = " + ExpressionToString(assignment.value());
1126
8.90k
  return assignment_str;
1127
8.90k
}
1128
1129
PROTO_TOSTRING(FieldSep, sep)
1130
10.9k
{
1131
10.9k
  using FieldSepType = FieldSep::SepOneofCase;
1132
10.9k
  switch (sep.sep_oneof_case()) {
1133
3.72k
  case FieldSepType::kComma:
1134
3.72k
    return ",";
1135
1.26k
  case FieldSepType::kSemicolon:
1136
1.26k
    return ";";
1137
5.99k
  default:
1138
5.99k
    return ",";
1139
10.9k
  }
1140
10.9k
}
1141
1142
/**
1143
 * Operators.
1144
 */
1145
PROTO_TOSTRING(BinaryOperator, op)
1146
23.8k
{
1147
23.8k
  using BinopType = BinaryOperator::BinaryOneofCase;
1148
23.8k
  switch (op.binary_oneof_case()) {
1149
521
  case BinopType::kAdd:
1150
521
    return "+";
1151
847
  case BinopType::kSub:
1152
847
    return "-";
1153
2.83k
  case BinopType::kMult:
1154
2.83k
    return "*";
1155
1.20k
  case BinopType::kDiv:
1156
1.20k
    return "/";
1157
678
  case BinopType::kExp:
1158
678
    return "^";
1159
822
  case BinopType::kMod:
1160
822
    return "%";
1161
1162
1.49k
  case BinopType::kConcat:
1163
1.49k
    return "..";
1164
1165
832
  case BinopType::kLess:
1166
832
    return "<";
1167
656
  case BinopType::kLessEqual:
1168
656
    return "<=";
1169
578
  case BinopType::kGreater:
1170
578
    return ">";
1171
269
  case BinopType::kGreaterEqual:
1172
269
    return ">=";
1173
375
  case BinopType::kEqual:
1174
375
    return "==";
1175
451
  case BinopType::kNotEqual:
1176
451
    return "~=";
1177
723
  case BinopType::kAnd:
1178
723
    return "and";
1179
3.57k
  case BinopType::kOr:
1180
3.57k
    return "or";
1181
7.97k
  default:
1182
    /* Works in most cases. */
1183
7.97k
    return "==";
1184
23.8k
  }
1185
23.8k
}
1186
1187
PROTO_TOSTRING(UnaryOperator, op)
1188
3.00k
{
1189
3.00k
  using UnaryopType = UnaryOperator::UnaryOneofCase;
1190
3.00k
  switch (op.unary_oneof_case()) {
1191
449
  case UnaryopType::kNegate:
1192
449
    return "-";
1193
358
  case UnaryopType::kNot:
1194
358
    return "not ";
1195
611
  case UnaryopType::kLength:
1196
611
    return "#";
1197
1.58k
  default:
1198
    /* Works in most cases. */
1199
1.58k
    return "not ";
1200
3.00k
  }
1201
3.00k
}
1202
1203
/**
1204
 * Identifier (Name).
1205
 */
1206
PROTO_TOSTRING(Name, name)
1207
294k
{
1208
294k
  std::string ident = ConvertToStringDefault(name.name());
1209
294k
  return ident + std::to_string(name.num() % kMaxIdentifiers);
1210
294k
}
1211
1212
} /* namespace */
1213
1214
std::string
1215
MainBlockToString(const Block &block)
1216
2.05k
{
1217
2.05k
  GetCounterIdProvider().clean();
1218
1219
2.05k
  std::string block_str = BlockToString(block);
1220
2.05k
  std::string retval = preamble_lua;
1221
1222
98.6k
  for (size_t i = 0; i < GetCounterIdProvider().count(); ++i) {
1223
96.6k
    retval += GetCounterName(i);
1224
96.6k
    retval += " = 0\n";
1225
96.6k
  }
1226
2.05k
  retval += block_str;
1227
1228
2.05k
  return retval;
1229
2.05k
}
1230
1231
} /* namespace luajit_fuzzer */