4 * A single-file Javascript-alike engine
6 * Authored By Gordon Williams <gw@pur3.co.uk>
8 * Copyright (C) 2009 Pur3 Ltd
10 * Permission is hereby granted, free of charge, to any person obtaining a copy of
11 * this software and associated documentation files (the "Software"), to deal in
12 * the Software without restriction, including without limitation the rights to
13 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
14 * of the Software, and to permit persons to whom the Software is furnished to do
15 * so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in all
18 * copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * This is a program to run all the tests in the tests folder...
44 //#define INSANE_MEMORY_DEBUG
46 #ifdef INSANE_MEMORY_DEBUG
47 // needs -rdynamic when compiling/linking
53 /* Prototypes for our hooks. */
54 static void *my_malloc_hook (size_t, const void *);
55 static void my_free_hook (void*, const void *);
56 static void *(*old_malloc_hook
) (size_t, const void *);
57 static void (*old_free_hook
) (void*, const void *);
60 std::map
<void*, void**> malloced
;
63 void **get_stackframe()
65 void **trace
= (void**)malloc(sizeof(void*)*17);
68 for (int i
=0; i
<17; i
++)
72 trace_size
= backtrace(trace
, 16);
76 void print_stackframe(char *header
, void **trace
)
78 char **messages
= (char **)NULL
;
81 while (trace
[trace_size
])
85 messages
= backtrace_symbols(trace
, trace_size
);
86 printf("%s\n", header
);
87 for (int i
=0; i
<trace_size
; ++i
)
89 printf("%s\n", messages
[i
]);
94 static void* my_malloc_hook(size_t size
, const void *caller
)
96 /* Restore all old hooks */
97 __malloc_hook
= old_malloc_hook
;
98 __free_hook
= old_free_hook
;
99 /* Call recursively */
100 void *result
= malloc (size
);
101 /* we call malloc here, so protect it too. */
102 //printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
103 malloced
[result
] = get_stackframe();
105 /* Restore our own hooks */
106 __malloc_hook
= my_malloc_hook
;
107 __free_hook
= my_free_hook
;
111 static void my_free_hook(void *ptr
, const void *caller
)
113 /* Restore all old hooks */
114 __malloc_hook
= old_malloc_hook
;
115 __free_hook
= old_free_hook
;
116 /* Call recursively */
118 /* we call malloc here, so protect it too. */
119 //printf ("freed pointer %p\n", ptr);
120 if(malloced
.find(ptr
) == malloced
.end())
123 fprintf(stderr, "INVALID FREE\n");
126 trace_size = backtrace(trace, 16);
127 backtrace_symbols_fd(trace, trace_size, STDERR_FILENO);
134 /* Restore our own hooks */
135 __malloc_hook
= my_malloc_hook
;
136 __free_hook
= my_free_hook
;
139 void memtracing_init()
141 old_malloc_hook
= __malloc_hook
;
142 old_free_hook
= __free_hook
;
143 __malloc_hook
= my_malloc_hook
;
144 __free_hook
= my_free_hook
;
147 long gethash(void **trace
)
149 unsigned long hash
= 0;
152 hash
= ((hash
<< 1)^(hash
>> 63) ^ ((unsigned long)(*trace
)));
158 void memtracing_kill()
165 std::map
<long, void**> hashToReal
;
166 std::map
<long, int> counts
;
167 std::vector
<std::pair
<int, long>> sorting
;
168 /* Restore all old hooks */
169 __malloc_hook
= old_malloc_hook
;
170 __free_hook
= old_free_hook
;
171 auto it
= malloced
.begin();
172 while (it
!=malloced
.end())
174 hash
= gethash(it
->second
);
175 hashToReal
[hash
] = it
->second
;
176 if (counts
.find(hash
) == counts
.end())
186 auto = counts
.begin();
187 while (countit
!= counts
.end())
189 sorting
.push_back(std::pair
<int, long>(countit
->second
, countit
->first
));
197 for(i
=0;i
<sorting
.size()-1;i
++)
199 if(sorting
[i
].first
< sorting
[i
+1].first
)
202 sorting
[i
] = sorting
[i
+1];
208 for(i
=0; i
<sorting
.size(); i
++)
210 hash
= sorting
[i
].second
;
211 count
= sorting
[i
].first
;
212 sprintf(header
, "--------------------------- LEAKED %d", count
);
213 print_stackframe(header
, hashToReal
[hash
]);
216 #endif // INSANE_MEMORY_DEBUG
219 TinyJS::Interpreter
* new_tjs()
221 auto s
= new TinyJS::Interpreter
;
222 TinyJS::registerFunctions(s
);
223 TinyJS::registerMathFunctions(s
);
227 bool fexists(const char* filename
, size_t* fsizedest
=NULL
)
230 if(stat(filename
, &st
) != 0)
232 if(fsizedest
!= NULL
)
234 (*fsizedest
) = st
.st_size
;
241 char* readFile(const char* filename
)
247 printf("TEST %s ", filename
);
248 if (fexists(filename
, &size
) == false)
250 printf("Cannot stat file '%s'\n", filename
);
253 file
= fopen(filename
, "rb");
254 /* if we open as text, the number of bytes read may be > the size we read */
257 printf("Unable to open file! '%s'\n", filename
);
260 buffer
= new char[size
+1];
261 actualsize
= fread(buffer
,1,size
,file
);
262 buffer
[actualsize
]=0;
268 bool run_test(const char *filename
)
273 TinyJS::Interpreter
* s
;
274 if((buffer
= readFile(filename
)) == NULL
)
279 s
->getRoot()->addChild("result", new TinyJS::Variable("0", TinyJS::SCRIPTVAR_INTEGER
));
284 catch(TinyJS::RuntimeError
*e
)
286 printf("ERROR: %s\n", e
->text
.c_str());
288 pass
= s
->getRoot()->getParameter("result")->getBool();
295 sprintf(fn
, "%s.fail.js", filename
);
296 FILE *f
= fopen(fn
, "wt");
299 std::ostringstream symbols
;
300 s
->getRoot()->getJSON(symbols
);
301 fprintf(f
, "%s", symbols
.str().c_str());
304 printf("FAIL - symbols written to %s\n", fn
);
310 int main(int argc
, char **argv
)
319 #ifdef INSANE_MEMORY_DEBUG
322 printf("TinyJS test runner\n");
324 printf(" ./run_tests test.js # run just one test\n");
325 printf(" ./run_tests # run all tests\n");
328 return !run_test(argv
[1]);
330 while (test_num
< 1000)
333 sprintf(fn
, "tests/test%03d.js", test_num
);
334 // check if the file exists - if not, assume we're at the end of our tests
335 if(fexists(fn
) == false)
346 printf("Done. %d tests, %d pass, %d fail\n", count
, passed
, count
-passed
);
347 #ifdef INSANE_MEMORY_DEBUG
352 _CrtDumpMemoryLeaks();