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 | | ** Prints an error message, adding the program name in front of it |
74 | | ** (if present) |
75 | | */ |
76 | 471 | static void l_message (const char *pname, const char *msg) { |
77 | 471 | if (pname) fprintf(stderr, "%s: ", pname); |
78 | 471 | fprintf(stderr, "%s\n", msg); |
79 | 471 | } |
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 | 475 | static int report (lua_State *L, int status) { |
88 | 475 | if (status != LUA_OK) { |
89 | 471 | const char *msg = lua_tostring(L, -1); |
90 | 471 | l_message(progname, msg); |
91 | 471 | lua_pop(L, 1); /* remove message */ |
92 | 471 | } |
93 | 475 | return status; |
94 | 475 | } |
95 | | |
96 | | /* |
97 | | ** Message handler used to run all chunks |
98 | | */ |
99 | 130 | static int msghandler (lua_State *L) { |
100 | 130 | const char *msg = lua_tostring(L, 1); |
101 | 130 | 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 | 130 | luaL_traceback(L, L, msg, 1); /* append a standard traceback */ |
110 | 130 | return 1; /* return the traceback */ |
111 | 130 | } |
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 | 134 | static int docall (lua_State *L, int narg, int nres) { |
119 | 134 | int status; |
120 | 134 | int base = lua_gettop(L) - narg; /* function index */ |
121 | 134 | lua_pushcfunction(L, msghandler); /* push message handler */ |
122 | 134 | lua_insert(L, base); /* put it under function and args */ |
123 | 134 | globalL = L; /* to be available to 'laction' */ |
124 | 134 | signal(SIGINT, laction); /* set C-signal handler */ |
125 | 134 | status = lua_pcall(L, narg, nres, base); |
126 | 134 | signal(SIGINT, SIG_DFL); /* reset C-signal handler */ |
127 | 134 | lua_remove(L, base); /* remove message handler from the stack */ |
128 | 134 | return status; |
129 | 134 | } |
130 | | |
131 | | |
132 | 475 | static int dochunk (lua_State *L, int status) { |
133 | 475 | if (status == LUA_OK) status = docall(L, 0, 0); |
134 | 475 | return report(L, status); |
135 | 475 | } |
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 | 13.9k | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
144 | 13.9k | lua_State *L = luaL_newstate(); |
145 | 13.9k | if (L == NULL) { |
146 | 0 | return 0; |
147 | 0 | } |
148 | 13.9k | dochunk(L, luaL_loadbufferx(L, (const char *)data, size, "test", "t")); |
149 | | |
150 | | |
151 | 13.9k | lua_close(L); |
152 | 13.9k | return 0; |
153 | 13.9k | } |