mirror of https://github.com/google/oss-fuzz.git
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;
|
||
|
}
|