1 // This file is distributed under the BSD License.
2 // See "license.txt" for details.
3 // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4 // Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
5 // http://www.chaiscript.com
6
7 // This is an open source non-commercial project. Dear PVS-Studio, please check it.
8 // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9
10
11 #include <iostream>
12 #include <list>
13 #include <regex>
14
15 #ifdef _MSC_VER
16 #define _CRT_SECURE_NO_WARNINGS
17 #endif
18
19 #include <chaiscript/chaiscript.hpp>
20 #include "../static_libs/chaiscript_parser.hpp"
21 #include "../static_libs/chaiscript_stdlib.hpp"
22
23 #include "sha3.h"
24
25 #ifdef READLINE_AVAILABLE
26 #include <readline/readline.h>
27 #include <readline/history.h>
28 #else
29
mystrdup(const char * s)30 char *mystrdup (const char *s) {
31 size_t len = strlen(s); // Space for length plus nul
32 char *d = static_cast<char*>(malloc (len+1));
33 if (d == nullptr) { return nullptr; } // No memory
34 #ifdef CHAISCRIPT_MSVC
35 strcpy_s(d, len+1, s); // Copy the characters
36 #else
37 strncpy(d,s,len); // Copy the characters
38 #endif
39 d[len] = '\0';
40 return d; // Return the new string
41 }
42
readline(const char * p)43 char* readline(const char* p)
44 {
45 std::string retval;
46 std::cout << p ;
47 std::getline(std::cin, retval);
48 return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
49 }
50
51
add_history(const char *)52 void add_history(const char* /*unused*/){}
using_history()53 void using_history(){}
54 #endif
55
56
57
cast_module_symbol(std::vector<std::string> (* t_path)())58 void *cast_module_symbol(std::vector<std::string> (*t_path)())
59 {
60 union cast_union
61 {
62 std::vector<std::string> (*in_ptr)();
63 void *out_ptr;
64 };
65
66 cast_union c;
67 c.in_ptr = t_path;
68 return c.out_ptr;
69 }
70
default_search_paths()71 std::vector<std::string> default_search_paths()
72 {
73 std::vector<std::string> paths;
74
75 #ifndef CHAISCRIPT_NO_DYNLOAD
76 #ifdef CHAISCRIPT_WINDOWS // force no unicode
77 CHAR path[4096];
78 int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
79
80 std::string exepath(path, size);
81
82 size_t lastslash = exepath.rfind('\\');
83 size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
84 if (lastslash != std::string::npos)
85 {
86 paths.push_back(exepath.substr(0, lastslash));
87 }
88
89 if (secondtolastslash != std::string::npos)
90 {
91 return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
92 }
93 #else
94
95 std::string exepath;
96
97 std::vector<char> buf(2048);
98 ssize_t size = -1;
99
100 if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
101 {
102 exepath = std::string(&buf.front(), static_cast<size_t>(size));
103 }
104
105 if (exepath.empty())
106 {
107 if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
108 {
109 exepath = std::string(&buf.front(), static_cast<size_t>(size));
110 }
111 }
112
113 if (exepath.empty())
114 {
115 if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
116 {
117 exepath = std::string(&buf.front(), static_cast<size_t>(size));
118 }
119 }
120
121 if (exepath.empty())
122 {
123 Dl_info rInfo;
124 memset( &rInfo, 0, sizeof(rInfo) );
125 if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
126 return paths;
127 }
128
129 exepath = std::string(rInfo.dli_fname);
130 }
131
132 size_t lastslash = exepath.rfind('/');
133
134 size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
135 if (lastslash != std::string::npos)
136 {
137 paths.push_back(exepath.substr(0, lastslash+1));
138 }
139
140 if (secondtolastslash != std::string::npos)
141 {
142 paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
143 }
144 #endif
145 #endif // ifndef CHAISCRIPT_NO_DYNLOAD
146
147 return paths;
148 }
149
help(int n)150 void help(int n) {
151 if ( n >= 0 ) {
152 std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
153 std::cout << "Additionally, you can inspect the runtime system using:\n";
154 std::cout << " dump_system() - outputs all functions registered to the system\n";
155 std::cout << " dump_object(x) - dumps information about the given symbol\n";
156 } else {
157 std::cout << "usage : chai [option]+\n";
158 std::cout << "option:" << '\n';
159 std::cout << " -h | --help" << '\n';
160 std::cout << " -i | --interactive" << '\n';
161 std::cout << " -c | --command cmd" << '\n';
162 std::cout << " -v | --version" << '\n';
163 std::cout << " - --stdin" << '\n';
164 std::cout << " filepath" << '\n';
165 }
166 }
167
throws_exception(const std::function<void ()> & f)168 bool throws_exception(const std::function<void ()> &f)
169 {
170 try {
171 f();
172 } catch (...) {
173 return true;
174 }
175
176 return false;
177 }
178
get_eval_error(const std::function<void ()> & f)179 chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
180 {
181 try {
182 f();
183 } catch (const chaiscript::exception::eval_error &e) {
184 return e;
185 }
186
187 throw std::runtime_error("no exception throw");
188 }
189
get_next_command()190 std::string get_next_command() {
191 std::string retval("quit");
192 if ( ! std::cin.eof() ) {
193 char *input_raw = readline("eval> ");
194 if ( input_raw != nullptr ) {
195 add_history(input_raw);
196
197 std::string val(input_raw);
198 size_t pos = val.find_first_not_of("\t \n");
199 if (pos != std::string::npos)
200 {
201 val.erase(0, pos);
202 }
203 pos = val.find_last_not_of("\t \n");
204 if (pos != std::string::npos)
205 {
206 val.erase(pos+1, std::string::npos);
207 }
208
209 retval = val;
210
211 ::free(input_raw);
212 }
213 }
214 if( retval == "quit"
215 || retval == "exit"
216 || retval == "help"
217 || retval == "version")
218 {
219 retval += "(0)";
220 }
221 return retval;
222 }
223
224 // We have to wrap exit with our own because Clang has a hard time with
225 // function pointers to functions with special attributes (system exit being marked NORETURN)
myexit(int return_val)226 void myexit(int return_val) {
227 exit(return_val);
228 }
229
interactive(chaiscript::ChaiScript_Basic & chai)230 void interactive(chaiscript::ChaiScript_Basic& chai)
231 {
232 using_history();
233
234 for (;;) {
235 std::string input = get_next_command();
236 try {
237 // evaluate input
238 chaiscript::Boxed_Value val = chai.eval(input);
239
240 //Then, we try to print the result of the evaluation to the user
241 if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
242 try {
243 std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
244 }
245 catch (...) {} //If we can't, do nothing
246 }
247 }
248 catch (const chaiscript::exception::eval_error &ee) {
249 std::cout << ee.what();
250 if ( !ee.call_stack.empty() ) {
251 std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
252 }
253 std::cout << '\n';
254 }
255 catch (const std::exception &e) {
256 std::cout << e.what();
257 std::cout << '\n';
258 }
259 }
260 }
261
now()262 double now()
263 {
264 using namespace std::chrono;
265 auto now = high_resolution_clock::now();
266 return duration_cast<duration<double>>(now.time_since_epoch()).count();
267 }
268
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)269 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
270 chaiscript::ChaiScript chai;
271
272 chai.eval( R"chaiscript(
273 def assert_equal(x, y)
274 {
275 if (x == y)
276 {
277 // Passes
278 } else {
279 // Fails
280 print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
281 // exit(-1);
282 }
283 }
284
285 def assert_false(f)
286 {
287 if (f)
288 {
289 print("assert_false failure");
290 // exit(-1);
291 }
292 }
293
294 def assert_true(f)
295 {
296 if (!f)
297 {
298 print("assert_true failure");
299 // exit(-1);
300 }
301 }
302
303 def assert_not_equal(x, y)
304 {
305 if (!(x == y))
306 {
307 // Passes
308 } else {
309 // Fails
310 print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
311 // exit(-1);
312 }
313 }
314
315 def assert_throws(desc, x)
316 {
317 if (throws_exception(x))
318 {
319 // Passes
320 } else {
321 // Fails
322 print("assert_throws failure, function did not throw exception: " + to_string(desc));
323 // exit(-1);
324 }
325 })chaiscript");
326
327 SHA3 sha3;
328 std::string sha = sha3(data, size);
329
330 std::string input(reinterpret_cast<const char *>(data), size);
331 try {
332 chai.eval(std::string(reinterpret_cast<const char *>(data), size));
333 std::ofstream ofs("VALID/" + sha);
334 ofs << input;
335 } catch (const chaiscript::exception::eval_error &) {
336 std::ofstream ofs("EVAL_ERROR/" + sha);
337 ofs << input;
338 } catch (const chaiscript::Boxed_Value &) {
339 std::ofstream ofs("BOXED_VALUE/" + sha);
340 ofs << input;
341 } catch (const chaiscript::exception::load_module_error &e) {
342 std::cout << "Unhandled module load error\n" << e.what() << '\n';
343 } catch (const std::exception &) {
344 std::ofstream ofs("STD_EXCEPTION/" + sha);
345 ofs << input;
346 } catch (...) {
347 std::ofstream ofs("UNKOWN_EXCEPTION/" + sha);
348 ofs << input;
349 }
350
351 return 0;
352 }
353
354
355