155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Copyright 2020 Google LLC
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|       http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| 
 | |
| #define lua_c
 | |
| 
 | |
| #include "lprefix.h"
 | |
| 
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| #include <signal.h>
 | |
| 
 | |
| #include "lua.h"
 | |
| 
 | |
| #include "lauxlib.h"
 | |
| #include "lualib.h"
 | |
| 
 | |
| 
 | |
| #if !defined(LUA_PROGNAME)
 | |
| #define LUA_PROGNAME            "lua"
 | |
| #endif
 | |
| 
 | |
| #if !defined(LUA_INIT_VAR)
 | |
| #define LUA_INIT_VAR            "LUA_INIT"
 | |
| #endif
 | |
| 
 | |
| #define LUA_INITVARVERSION      LUA_INIT_VAR LUA_VERSUFFIX
 | |
| 
 | |
| 
 | |
| static lua_State *globalL = NULL;
 | |
| 
 | |
| static const char *progname = LUA_PROGNAME;
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Hook set by signal function to stop the interpreter.
 | |
| */
 | |
| static void lstop (lua_State *L, lua_Debug *ar) {
 | |
|   (void)ar;  /* unused arg. */
 | |
|   lua_sethook(L, NULL, 0, 0);  /* reset hook */
 | |
|   luaL_error(L, "interrupted!");
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Function to be called at a C signal. Because a C signal cannot
 | |
| ** just change a Lua state (as there is no proper synchronization),
 | |
| ** this function only sets a hook that, when called, will stop the
 | |
| ** interpreter.
 | |
| */
 | |
| static void laction (int i) {
 | |
|   int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
 | |
|   signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
 | |
|   lua_sethook(globalL, lstop, flag, 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Prints an error message, adding the program name in front of it
 | |
| ** (if present)
 | |
| */
 | |
| static void l_message (const char *pname, const char *msg) {
 | |
|   if (pname) lua_writestringerror("%s: ", pname);
 | |
|   lua_writestringerror("%s\n", msg);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Check whether 'status' is not OK and, if so, prints the error
 | |
| ** message on the top of the stack. It assumes that the error object
 | |
| ** is a string, as it was either generated by Lua or by 'msghandler'.
 | |
| */
 | |
| static int report (lua_State *L, int status) {
 | |
|   if (status != LUA_OK) {
 | |
|     const char *msg = lua_tostring(L, -1);
 | |
|     l_message(progname, msg);
 | |
|     lua_pop(L, 1);  /* remove message */
 | |
|   }
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Message handler used to run all chunks
 | |
| */
 | |
| static int msghandler (lua_State *L) {
 | |
|   const char *msg = lua_tostring(L, 1);
 | |
|   if (msg == NULL) {  /* is error object not a string? */
 | |
|     if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
 | |
|         lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
 | |
|       return 1;  /* that is the message */
 | |
|     else
 | |
|       msg = lua_pushfstring(L, "(error object is a %s value)",
 | |
|                                luaL_typename(L, 1));
 | |
|   }
 | |
|   luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
 | |
|   return 1;  /* return the traceback */
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Interface to 'lua_pcall', which sets appropriate message function
 | |
| ** and C-signal handler. Used to run all chunks.
 | |
| */
 | |
| static int docall (lua_State *L, int narg, int nres) {
 | |
|   int status;
 | |
|   int base = lua_gettop(L) - narg;  /* function index */
 | |
|   lua_pushcfunction(L, msghandler);  /* push message handler */
 | |
|   lua_insert(L, base);  /* put it under function and args */
 | |
|   globalL = L;  /* to be available to 'laction' */
 | |
|   signal(SIGINT, laction);  /* set C-signal handler */
 | |
|   status = lua_pcall(L, narg, nres, base);
 | |
|   signal(SIGINT, SIG_DFL); /* reset C-signal handler */
 | |
|   lua_remove(L, base);  /* remove message handler from the stack */
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int dochunk (lua_State *L, int status) {
 | |
|   if (status == LUA_OK) status = docall(L, 0, 0);
 | |
|   return report(L, status);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* mark in error messages for incomplete statements */
 | |
| #define EOFMARK         "<eof>"
 | |
| #define marklen         (sizeof(EOFMARK)/sizeof(char) - 1)
 | |
| 
 | |
| int
 | |
| LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 | |
|     lua_State *L = luaL_newstate();
 | |
|     if (L == NULL) {
 | |
|         return 0;
 | |
|     }
 | |
|     dochunk(L, luaL_loadbufferx(L, data, size, "test", "t"));
 | |
| 
 | |
|     lua_close(L);
 | |
|     return 0;
 | |
| }
 |