Coverage Report

Created: 2025-10-13 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fuzz_lua.c
Line
Count
Source
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
** Prints an error message, adding the program name in front of it
74
** (if present)
75
*/
76
451
static void l_message (const char *pname, const char *msg) {
77
451
  if (pname) fprintf(stderr, "%s: ", pname);
78
451
  fprintf(stderr, "%s\n", msg);
79
451
}
80
81
82
/*
83
** Check whether 'status' is not OK and, if so, prints the error
84
** message on the top of the stack. It assumes that the error object
85
** is a string, as it was either generated by Lua or by 'msghandler'.
86
*/
87
453
static int report (lua_State *L, int status) {
88
453
  if (status != LUA_OK) {
89
451
    const char *msg = lua_tostring(L, -1);
90
451
    l_message(progname, msg);
91
451
    lua_pop(L, 1);  /* remove message */
92
451
  }
93
453
  return status;
94
453
}
95
96
/*
97
** Message handler used to run all chunks
98
*/
99
150
static int msghandler (lua_State *L) {
100
150
  const char *msg = lua_tostring(L, 1);
101
150
  if (msg == NULL) {  /* is error object not a string? */
102
0
    if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
103
0
        lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
104
0
      return 1;  /* that is the message */
105
0
    else
106
0
      msg = lua_pushfstring(L, "(error object is a %s value)",
107
0
                               luaL_typename(L, 1));
108
0
  }
109
150
  luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
110
150
  return 1;  /* return the traceback */
111
150
}
112
113
114
/*
115
** Interface to 'lua_pcall', which sets appropriate message function
116
** and C-signal handler. Used to run all chunks.
117
*/
118
152
static int docall (lua_State *L, int narg, int nres) {
119
152
  int status;
120
152
  int base = lua_gettop(L) - narg;  /* function index */
121
152
  lua_pushcfunction(L, msghandler);  /* push message handler */
122
152
  lua_insert(L, base);  /* put it under function and args */
123
152
  globalL = L;  /* to be available to 'laction' */
124
152
  signal(SIGINT, laction);  /* set C-signal handler */
125
152
  status = lua_pcall(L, narg, nres, base);
126
152
  signal(SIGINT, SIG_DFL); /* reset C-signal handler */
127
152
  lua_remove(L, base);  /* remove message handler from the stack */
128
152
  return status;
129
152
}
130
131
132
453
static int dochunk (lua_State *L, int status) {
133
453
  if (status == LUA_OK) status = docall(L, 0, 0);
134
453
  return report(L, status);
135
453
}
136
137
138
/* mark in error messages for incomplete statements */
139
#define EOFMARK         "<eof>"
140
#define marklen         (sizeof(EOFMARK)/sizeof(char) - 1)
141
142
int
143
14.1k
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
144
14.1k
    lua_State *L = luaL_newstate();
145
14.1k
    if (L == NULL) {
146
0
        return 0;
147
0
    }
148
14.1k
    dochunk(L, luaL_loadbufferx(L, (const char *)data, size, "test", "t"));
149
150
151
14.1k
    lua_close(L);
152
14.1k
    return 0;
153
14.1k
}