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