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 | 382 | static void l_message (const char *pname, const char *msg) { |
79 | 382 | if (pname) lua_writestringerror("%s: ", pname); |
80 | 382 | lua_writestringerror("%s\n", msg); |
81 | 382 | } |
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 | 390 | static int report (lua_State *L, int status) { |
90 | 390 | if (status != LUA_OK) { |
91 | 382 | const char *msg = lua_tostring(L, -1); |
92 | 382 | l_message(progname, msg); |
93 | 382 | lua_pop(L, 1); /* remove message */ |
94 | 382 | } |
95 | 390 | return status; |
96 | 390 | } |
97 | | |
98 | | /* |
99 | | ** Message handler used to run all chunks |
100 | | */ |
101 | 56 | static int msghandler (lua_State *L) { |
102 | 56 | const char *msg = lua_tostring(L, 1); |
103 | 56 | 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 | 56 | luaL_traceback(L, L, msg, 1); /* append a standard traceback */ |
112 | 56 | return 1; /* return the traceback */ |
113 | 56 | } |
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 | 64 | static int docall (lua_State *L, int narg, int nres) { |
121 | 64 | int status; |
122 | 64 | int base = lua_gettop(L) - narg; /* function index */ |
123 | 64 | lua_pushcfunction(L, msghandler); /* push message handler */ |
124 | 64 | lua_insert(L, base); /* put it under function and args */ |
125 | 64 | globalL = L; /* to be available to 'laction' */ |
126 | 64 | signal(SIGINT, laction); /* set C-signal handler */ |
127 | 64 | status = lua_pcall(L, narg, nres, base); |
128 | 64 | signal(SIGINT, SIG_DFL); /* reset C-signal handler */ |
129 | 64 | lua_remove(L, base); /* remove message handler from the stack */ |
130 | 64 | return status; |
131 | 64 | } |
132 | | |
133 | | |
134 | 390 | static int dochunk (lua_State *L, int status) { |
135 | 390 | if (status == LUA_OK) status = docall(L, 0, 0); |
136 | 390 | return report(L, status); |
137 | 390 | } |
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 | 9.57k | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
146 | 9.57k | lua_State *L = luaL_newstate(); |
147 | 9.57k | if (L == NULL) { |
148 | 0 | return 0; |
149 | 0 | } |
150 | 9.57k | dochunk(L, luaL_loadbufferx(L, (const char *)data, size, "test", "t")); |
151 | | |
152 | | |
153 | 9.57k | lua_close(L); |
154 | 9.57k | return 0; |
155 | 9.57k | } |