• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
lstop(lua_State * L,lua_Debug * ar)53 static void lstop (lua_State *L, lua_Debug *ar) {
54   (void)ar;  /* unused arg. */
55   lua_sethook(L, NULL, 0, 0);  /* reset hook */
56   luaL_error(L, "interrupted!");
57 }
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 */
laction(int i)66 static void laction (int i) {
67   int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
68   signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
69   lua_sethook(globalL, lstop, flag, 1);
70 }
71 
72 
73 
74 /*
75 ** Prints an error message, adding the program name in front of it
76 ** (if present)
77 */
l_message(const char * pname,const char * msg)78 static void l_message (const char *pname, const char *msg) {
79   if (pname) lua_writestringerror("%s: ", pname);
80   lua_writestringerror("%s\n", msg);
81 }
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 */
report(lua_State * L,int status)89 static int report (lua_State *L, int status) {
90   if (status != LUA_OK) {
91     const char *msg = lua_tostring(L, -1);
92     l_message(progname, msg);
93     lua_pop(L, 1);  /* remove message */
94   }
95   return status;
96 }
97 
98 /*
99 ** Message handler used to run all chunks
100 */
msghandler(lua_State * L)101 static int msghandler (lua_State *L) {
102   const char *msg = lua_tostring(L, 1);
103   if (msg == NULL) {  /* is error object not a string? */
104     if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
105         lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
106       return 1;  /* that is the message */
107     else
108       msg = lua_pushfstring(L, "(error object is a %s value)",
109                                luaL_typename(L, 1));
110   }
111   luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
112   return 1;  /* return the traceback */
113 }
114 
115 
116 /*
117 ** Interface to 'lua_pcall', which sets appropriate message function
118 ** and C-signal handler. Used to run all chunks.
119 */
docall(lua_State * L,int narg,int nres)120 static int docall (lua_State *L, int narg, int nres) {
121   int status;
122   int base = lua_gettop(L) - narg;  /* function index */
123   lua_pushcfunction(L, msghandler);  /* push message handler */
124   lua_insert(L, base);  /* put it under function and args */
125   globalL = L;  /* to be available to 'laction' */
126   signal(SIGINT, laction);  /* set C-signal handler */
127   status = lua_pcall(L, narg, nres, base);
128   signal(SIGINT, SIG_DFL); /* reset C-signal handler */
129   lua_remove(L, base);  /* remove message handler from the stack */
130   return status;
131 }
132 
133 
dochunk(lua_State * L,int status)134 static int dochunk (lua_State *L, int status) {
135   if (status == LUA_OK) status = docall(L, 0, 0);
136   return report(L, status);
137 }
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
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)145 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
146     lua_State *L = luaL_newstate();
147     if (L == NULL) {
148         return 0;
149     }
150     dochunk(L, luaL_loadbufferx(L, data, size, "test", "t"));
151 
152     lua_close(L);
153     return 0;
154 }
155