Coverage Report

Created: 2023-09-20 06:32

/src/fuzz_lua.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2020 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
6
      http://www.apache.org/licenses/LICENSE-2.0
7
8
Unless required by applicable law or agreed to in writing, software
9
distributed under the License is distributed on an "AS IS" BASIS,
10
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
See the License for the specific language governing permissions and
12
limitations under the License.
13
*/
14
15
16
#define lua_c
17
18
#include "lprefix.h"
19
20
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <stdint.h>
25
26
#include <signal.h>
27
28
#include "lua.h"
29
30
#include "lauxlib.h"
31
#include "lualib.h"
32
33
34
#if !defined(LUA_PROGNAME)
35
#define LUA_PROGNAME            "lua"
36
#endif
37
38
#if !defined(LUA_INIT_VAR)
39
#define LUA_INIT_VAR            "LUA_INIT"
40
#endif
41
42
#define LUA_INITVARVERSION      LUA_INIT_VAR LUA_VERSUFFIX
43
44
45
static lua_State *globalL = NULL;
46
47
static const char *progname = LUA_PROGNAME;
48
49
50
/*
51
** Hook set by signal function to stop the interpreter.
52
*/
53
0
static void lstop (lua_State *L, lua_Debug *ar) {
54
0
  (void)ar;  /* unused arg. */
55
0
  lua_sethook(L, NULL, 0, 0);  /* reset hook */
56
0
  luaL_error(L, "interrupted!");
57
0
}
58
59
60
/*
61
** Function to be called at a C signal. Because a C signal cannot
62
** just change a Lua state (as there is no proper synchronization),
63
** this function only sets a hook that, when called, will stop the
64
** interpreter.
65
*/
66
0
static void laction (int i) {
67
0
  int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
68
0
  signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
69
0
  lua_sethook(globalL, lstop, flag, 1);
70
0
}
71
72
73
74
/*
75
** Prints an error message, adding the program name in front of it
76
** (if present)
77
*/
78
302
static void l_message (const char *pname, const char *msg) {
79
302
  if (pname) lua_writestringerror("%s: ", pname);
80
302
  lua_writestringerror("%s\n", msg);
81
302
}
82
83
84
/*
85
** Check whether 'status' is not OK and, if so, prints the error
86
** message on the top of the stack. It assumes that the error object
87
** is a string, as it was either generated by Lua or by 'msghandler'.
88
*/
89
308
static int report (lua_State *L, int status) {
90
308
  if (status != LUA_OK) {
91
302
    const char *msg = lua_tostring(L, -1);
92
302
    l_message(progname, msg);
93
302
    lua_pop(L, 1);  /* remove message */
94
302
  }
95
308
  return status;
96
308
}
97
98
/*
99
** Message handler used to run all chunks
100
*/
101
41
static int msghandler (lua_State *L) {
102
41
  const char *msg = lua_tostring(L, 1);
103
41
  if (msg == NULL) {  /* is error object not a string? */
104
0
    if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
105
0
        lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
106
0
      return 1;  /* that is the message */
107
0
    else
108
0
      msg = lua_pushfstring(L, "(error object is a %s value)",
109
0
                               luaL_typename(L, 1));
110
0
  }
111
41
  luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
112
41
  return 1;  /* return the traceback */
113
41
}
114
115
116
/*
117
** Interface to 'lua_pcall', which sets appropriate message function
118
** and C-signal handler. Used to run all chunks.
119
*/
120
47
static int docall (lua_State *L, int narg, int nres) {
121
47
  int status;
122
47
  int base = lua_gettop(L) - narg;  /* function index */
123
47
  lua_pushcfunction(L, msghandler);  /* push message handler */
124
47
  lua_insert(L, base);  /* put it under function and args */
125
47
  globalL = L;  /* to be available to 'laction' */
126
47
  signal(SIGINT, laction);  /* set C-signal handler */
127
47
  status = lua_pcall(L, narg, nres, base);
128
47
  signal(SIGINT, SIG_DFL); /* reset C-signal handler */
129
47
  lua_remove(L, base);  /* remove message handler from the stack */
130
47
  return status;
131
47
}
132
133
134
308
static int dochunk (lua_State *L, int status) {
135
308
  if (status == LUA_OK) status = docall(L, 0, 0);
136
308
  return report(L, status);
137
308
}
138
139
140
/* mark in error messages for incomplete statements */
141
#define EOFMARK         "<eof>"
142
#define marklen         (sizeof(EOFMARK)/sizeof(char) - 1)
143
144
int
145
308
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
146
308
    lua_State *L = luaL_newstate();
147
308
    if (L == NULL) {
148
0
        return 0;
149
0
    }
150
308
    dochunk(L, luaL_loadbufferx(L, (const char *)data, size, "test", "t"));
151
152
153
308
    lua_close(L);
154
308
    return 0;
155
308
}