bcheck.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. /*
  2. * Tiny C Memory and bounds checker
  3. *
  4. * Copyright (c) 2002 Fabrice Bellard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #if !defined(__FreeBSD__) \
  25. && !defined(__FreeBSD_kernel__) \
  26. && !defined(__DragonFly__) \
  27. && !defined(__OpenBSD__) \
  28. && !defined(__NetBSD__)
  29. #include <malloc.h>
  30. #endif
  31. #if !defined(_WIN32)
  32. #include <unistd.h>
  33. #endif
  34. /* #define BOUND_DEBUG */
  35. #ifdef BOUND_DEBUG
  36. #define dprintf(a...) fprintf(a)
  37. #else
  38. #define dprintf(a...)
  39. #endif
  40. /* define so that bound array is static (faster, but use memory if
  41. bound checking not used) */
  42. /* #define BOUND_STATIC */
  43. /* use malloc hooks. Currently the code cannot be reliable if no hooks */
  44. #define CONFIG_TCC_MALLOC_HOOKS
  45. #define HAVE_MEMALIGN
  46. #if defined(__FreeBSD__) \
  47. || defined(__FreeBSD_kernel__) \
  48. || defined(__DragonFly__) \
  49. || defined(__OpenBSD__) \
  50. || defined(__NetBSD__) \
  51. || defined(__dietlibc__) \
  52. || defined(_WIN32)
  53. //#warning Bound checking does not support malloc (etc.) in this environment.
  54. #undef CONFIG_TCC_MALLOC_HOOKS
  55. #undef HAVE_MEMALIGN
  56. #endif
  57. #define BOUND_T1_BITS 13
  58. #define BOUND_T2_BITS 11
  59. #define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS)
  60. #define BOUND_E_BITS (sizeof(size_t))
  61. #define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS)
  62. #define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS)
  63. #define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS)
  64. #define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
  65. #define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS)
  66. /* this pointer is generated when bound check is incorrect */
  67. #define INVALID_POINTER ((void *)(-2))
  68. /* size of an empty region */
  69. #define EMPTY_SIZE ((size_t)(-1))
  70. /* size of an invalid region */
  71. #define INVALID_SIZE 0
  72. typedef struct BoundEntry {
  73. size_t start;
  74. size_t size;
  75. struct BoundEntry *next;
  76. size_t is_invalid; /* true if pointers outside region are invalid */
  77. } BoundEntry;
  78. /* external interface */
  79. void __bound_init(void);
  80. void __bound_new_region(void *p, size_t size);
  81. int __bound_delete_region(void *p);
  82. #ifdef __attribute__
  83. /* an __attribute__ macro is defined in the system headers */
  84. #undef __attribute__
  85. #endif
  86. #define FASTCALL __attribute__((regparm(3)))
  87. void *__bound_malloc(size_t size, const void *caller);
  88. void *__bound_memalign(size_t size, size_t align, const void *caller);
  89. void __bound_free(void *ptr, const void *caller);
  90. void *__bound_realloc(void *ptr, size_t size, const void *caller);
  91. static void *libc_malloc(size_t size);
  92. static void libc_free(void *ptr);
  93. static void install_malloc_hooks(void);
  94. static void restore_malloc_hooks(void);
  95. #ifdef CONFIG_TCC_MALLOC_HOOKS
  96. static void *saved_malloc_hook;
  97. static void *saved_free_hook;
  98. static void *saved_realloc_hook;
  99. static void *saved_memalign_hook;
  100. #endif
  101. /* TCC definitions */
  102. extern char __bounds_start; /* start of static bounds table */
  103. /* error message, just for TCC */
  104. const char *__bound_error_msg;
  105. /* runtime error output */
  106. extern void rt_error(size_t pc, const char *fmt, ...);
  107. #ifdef BOUND_STATIC
  108. static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
  109. #else
  110. static BoundEntry **__bound_t1; /* page table */
  111. #endif
  112. static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
  113. static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
  114. static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
  115. {
  116. size_t addr, tmp;
  117. BoundEntry *e;
  118. e = e1;
  119. while (e != NULL) {
  120. addr = (size_t)p;
  121. addr -= e->start;
  122. if (addr <= e->size) {
  123. /* put region at the head */
  124. tmp = e1->start;
  125. e1->start = e->start;
  126. e->start = tmp;
  127. tmp = e1->size;
  128. e1->size = e->size;
  129. e->size = tmp;
  130. return e1;
  131. }
  132. e = e->next;
  133. }
  134. /* no entry found: return empty entry or invalid entry */
  135. if (e1->is_invalid)
  136. return __bound_invalid_t2;
  137. else
  138. return __bound_empty_t2;
  139. }
  140. /* print a bound error message */
  141. static void bound_error(const char *fmt, ...)
  142. {
  143. __bound_error_msg = fmt;
  144. fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt);
  145. *(void **)0 = 0; /* force a runtime error */
  146. }
  147. static void bound_alloc_error(void)
  148. {
  149. bound_error("not enough memory for bound checking code");
  150. }
  151. /* return '(p + offset)' for pointer arithmetic (a pointer can reach
  152. the end of a region in this case */
  153. void * FASTCALL __bound_ptr_add(void *p, size_t offset)
  154. {
  155. size_t addr = (size_t)p;
  156. BoundEntry *e;
  157. dprintf(stderr, "%s %s: %p %x\n",
  158. __FILE__, __FUNCTION__, p, (unsigned)offset);
  159. __bound_init();
  160. e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
  161. e = (BoundEntry *)((char *)e +
  162. ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  163. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
  164. addr -= e->start;
  165. if (addr > e->size) {
  166. e = __bound_find_region(e, p);
  167. addr = (size_t)p - e->start;
  168. }
  169. addr += offset;
  170. if (addr >= e->size) {
  171. fprintf(stderr,"%s %s: %p is outside of the region\n",
  172. __FILE__, __FUNCTION__, p + offset);
  173. return INVALID_POINTER; /* return an invalid pointer */
  174. }
  175. return p + offset;
  176. }
  177. /* return '(p + offset)' for pointer indirection (the resulting must
  178. be strictly inside the region */
  179. #define BOUND_PTR_INDIR(dsize) \
  180. void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
  181. { \
  182. size_t addr = (size_t)p; \
  183. BoundEntry *e; \
  184. \
  185. dprintf(stderr, "%s %s: %p %x start\n", \
  186. __FILE__, __FUNCTION__, p, (unsigned)offset); \
  187. \
  188. __bound_init(); \
  189. e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
  190. e = (BoundEntry *)((char *)e + \
  191. ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
  192. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
  193. addr -= e->start; \
  194. if (addr > e->size) { \
  195. e = __bound_find_region(e, p); \
  196. addr = (size_t)p - e->start; \
  197. } \
  198. addr += offset + dsize; \
  199. if (addr > e->size) { \
  200. fprintf(stderr,"%s %s: %p is outside of the region\n", \
  201. __FILE__, __FUNCTION__, p + offset); \
  202. return INVALID_POINTER; /* return an invalid pointer */ \
  203. } \
  204. dprintf(stderr, "%s %s: return p+offset = %p\n", \
  205. __FILE__, __FUNCTION__, p + offset); \
  206. return p + offset; \
  207. }
  208. BOUND_PTR_INDIR(1)
  209. BOUND_PTR_INDIR(2)
  210. BOUND_PTR_INDIR(4)
  211. BOUND_PTR_INDIR(8)
  212. BOUND_PTR_INDIR(12)
  213. BOUND_PTR_INDIR(16)
  214. #if defined(__GNUC__) && (__GNUC__ >= 6)
  215. /*
  216. * At least gcc 6.2 complains when __builtin_frame_address is used with
  217. * nonzero argument.
  218. */
  219. #pragma GCC diagnostic push
  220. #pragma GCC diagnostic ignored "-Wframe-address"
  221. #endif
  222. /* return the frame pointer of the caller */
  223. #define GET_CALLER_FP(fp)\
  224. {\
  225. fp = (size_t)__builtin_frame_address(1);\
  226. }
  227. /* called when entering a function to add all the local regions */
  228. void FASTCALL __bound_local_new(void *p1)
  229. {
  230. size_t addr, size, fp, *p = p1;
  231. dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p);
  232. GET_CALLER_FP(fp);
  233. for(;;) {
  234. addr = p[0];
  235. if (addr == 0)
  236. break;
  237. addr += fp;
  238. size = p[1];
  239. p += 2;
  240. __bound_new_region((void *)addr, size);
  241. }
  242. dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
  243. }
  244. /* called when leaving a function to delete all the local regions */
  245. void FASTCALL __bound_local_delete(void *p1)
  246. {
  247. size_t addr, fp, *p = p1;
  248. GET_CALLER_FP(fp);
  249. for(;;) {
  250. addr = p[0];
  251. if (addr == 0)
  252. break;
  253. addr += fp;
  254. p += 2;
  255. __bound_delete_region((void *)addr);
  256. }
  257. }
  258. #if defined(__GNUC__) && (__GNUC__ >= 6)
  259. #pragma GCC diagnostic pop
  260. #endif
  261. static BoundEntry *__bound_new_page(void)
  262. {
  263. BoundEntry *page;
  264. size_t i;
  265. page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
  266. if (!page)
  267. bound_alloc_error();
  268. for(i=0;i<BOUND_T2_SIZE;i++) {
  269. /* put empty entries */
  270. page[i].start = 0;
  271. page[i].size = EMPTY_SIZE;
  272. page[i].next = NULL;
  273. page[i].is_invalid = 0;
  274. }
  275. return page;
  276. }
  277. /* currently we use malloc(). Should use bound_new_page() */
  278. static BoundEntry *bound_new_entry(void)
  279. {
  280. BoundEntry *e;
  281. e = libc_malloc(sizeof(BoundEntry));
  282. return e;
  283. }
  284. static void bound_free_entry(BoundEntry *e)
  285. {
  286. libc_free(e);
  287. }
  288. static BoundEntry *get_page(size_t index)
  289. {
  290. BoundEntry *page;
  291. page = __bound_t1[index];
  292. if (!page || page == __bound_empty_t2 || page == __bound_invalid_t2) {
  293. /* create a new page if necessary */
  294. page = __bound_new_page();
  295. __bound_t1[index] = page;
  296. }
  297. return page;
  298. }
  299. /* mark a region as being invalid (can only be used during init) */
  300. static void mark_invalid(size_t addr, size_t size)
  301. {
  302. size_t start, end;
  303. BoundEntry *page;
  304. size_t t1_start, t1_end, i, j, t2_start, t2_end;
  305. start = addr;
  306. end = addr + size;
  307. t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
  308. if (end != 0)
  309. t2_end = end >> BOUND_T3_BITS;
  310. else
  311. t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
  312. #if 0
  313. dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end);
  314. #endif
  315. /* first we handle full pages */
  316. t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
  317. t1_end = t2_end >> BOUND_T2_BITS;
  318. i = t2_start & (BOUND_T2_SIZE - 1);
  319. j = t2_end & (BOUND_T2_SIZE - 1);
  320. if (t1_start == t1_end) {
  321. page = get_page(t2_start >> BOUND_T2_BITS);
  322. for(; i < j; i++) {
  323. page[i].size = INVALID_SIZE;
  324. page[i].is_invalid = 1;
  325. }
  326. } else {
  327. if (i > 0) {
  328. page = get_page(t2_start >> BOUND_T2_BITS);
  329. for(; i < BOUND_T2_SIZE; i++) {
  330. page[i].size = INVALID_SIZE;
  331. page[i].is_invalid = 1;
  332. }
  333. }
  334. for(i = t1_start; i < t1_end; i++) {
  335. __bound_t1[i] = __bound_invalid_t2;
  336. }
  337. if (j != 0) {
  338. page = get_page(t1_end);
  339. for(i = 0; i < j; i++) {
  340. page[i].size = INVALID_SIZE;
  341. page[i].is_invalid = 1;
  342. }
  343. }
  344. }
  345. }
  346. void __bound_init(void)
  347. {
  348. size_t i;
  349. BoundEntry *page;
  350. size_t start, size;
  351. size_t *p;
  352. static int inited;
  353. if (inited)
  354. return;
  355. inited = 1;
  356. dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
  357. /* save malloc hooks and install bound check hooks */
  358. install_malloc_hooks();
  359. #ifndef BOUND_STATIC
  360. __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
  361. if (!__bound_t1)
  362. bound_alloc_error();
  363. #endif
  364. __bound_empty_t2 = __bound_new_page();
  365. for(i=0;i<BOUND_T1_SIZE;i++) {
  366. __bound_t1[i] = __bound_empty_t2;
  367. }
  368. page = __bound_new_page();
  369. for(i=0;i<BOUND_T2_SIZE;i++) {
  370. /* put invalid entries */
  371. page[i].start = 0;
  372. page[i].size = INVALID_SIZE;
  373. page[i].next = NULL;
  374. page[i].is_invalid = 1;
  375. }
  376. __bound_invalid_t2 = page;
  377. /* invalid pointer zone */
  378. start = (size_t)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
  379. size = BOUND_T23_SIZE;
  380. mark_invalid(start, size);
  381. #if defined(CONFIG_TCC_MALLOC_HOOKS)
  382. /* malloc zone is also marked invalid. can only use that with
  383. * hooks because all libs should use the same malloc. The solution
  384. * would be to build a new malloc for tcc.
  385. *
  386. * usually heap (= malloc zone) comes right after bss, i.e. after _end, but
  387. * not always - either if we are running from under `tcc -b -run`, or if
  388. * address space randomization is turned on(a), heap start will be separated
  389. * from bss end.
  390. *
  391. * So sbrk(0) will be a good approximation for start_brk:
  392. *
  393. * - if we are a separately compiled program, __bound_init() runs early,
  394. * and sbrk(0) should be equal or very near to start_brk(b) (in case other
  395. * constructors malloc something), or
  396. *
  397. * - if we are running from under `tcc -b -run`, sbrk(0) will return
  398. * start of heap portion which is under this program control, and not
  399. * mark as invalid earlier allocated memory.
  400. *
  401. *
  402. * (a) /proc/sys/kernel/randomize_va_space = 2, on Linux;
  403. * usually turned on by default.
  404. *
  405. * (b) on Linux >= v3.3, the alternative is to read
  406. * start_brk from /proc/self/stat
  407. */
  408. start = (size_t)sbrk(0);
  409. size = 128 * 0x100000;
  410. mark_invalid(start, size);
  411. #endif
  412. /* add all static bound check values */
  413. p = (size_t *)&__bounds_start;
  414. while (p[0] != 0) {
  415. __bound_new_region((void *)p[0], p[1]);
  416. p += 2;
  417. }
  418. dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
  419. }
  420. void __bound_main_arg(void **p)
  421. {
  422. void *start = p;
  423. while (*p++);
  424. dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n",
  425. __FILE__, __FUNCTION__, start, (unsigned)((void *)p - start));
  426. __bound_new_region(start, (void *) p - start);
  427. }
  428. void __bound_exit(void)
  429. {
  430. dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
  431. restore_malloc_hooks();
  432. }
  433. static inline void add_region(BoundEntry *e,
  434. size_t start, size_t size)
  435. {
  436. BoundEntry *e1;
  437. if (e->start == 0) {
  438. /* no region : add it */
  439. e->start = start;
  440. e->size = size;
  441. } else {
  442. /* already regions in the list: add it at the head */
  443. e1 = bound_new_entry();
  444. e1->start = e->start;
  445. e1->size = e->size;
  446. e1->next = e->next;
  447. e->start = start;
  448. e->size = size;
  449. e->next = e1;
  450. }
  451. }
  452. /* create a new region. It should not already exist in the region list */
  453. void __bound_new_region(void *p, size_t size)
  454. {
  455. size_t start, end;
  456. BoundEntry *page, *e, *e2;
  457. size_t t1_start, t1_end, i, t2_start, t2_end;
  458. dprintf(stderr, "%s, %s(%p, %x) start\n",
  459. __FILE__, __FUNCTION__, p, (unsigned)size);
  460. __bound_init();
  461. start = (size_t)p;
  462. end = start + size;
  463. t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
  464. t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
  465. /* start */
  466. page = get_page(t1_start);
  467. t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  468. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
  469. t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  470. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
  471. e = (BoundEntry *)((char *)page + t2_start);
  472. add_region(e, start, size);
  473. if (t1_end == t1_start) {
  474. /* same ending page */
  475. e2 = (BoundEntry *)((char *)page + t2_end);
  476. if (e2 > e) {
  477. e++;
  478. for(;e<e2;e++) {
  479. e->start = start;
  480. e->size = size;
  481. }
  482. add_region(e, start, size);
  483. }
  484. } else {
  485. /* mark until end of page */
  486. e2 = page + BOUND_T2_SIZE;
  487. e++;
  488. for(;e<e2;e++) {
  489. e->start = start;
  490. e->size = size;
  491. }
  492. /* mark intermediate pages, if any */
  493. for(i=t1_start+1;i<t1_end;i++) {
  494. page = get_page(i);
  495. e2 = page + BOUND_T2_SIZE;
  496. for(e=page;e<e2;e++) {
  497. e->start = start;
  498. e->size = size;
  499. }
  500. }
  501. /* last page */
  502. page = get_page(t1_end);
  503. e2 = (BoundEntry *)((char *)page + t2_end);
  504. for(e=page;e<e2;e++) {
  505. e->start = start;
  506. e->size = size;
  507. }
  508. add_region(e, start, size);
  509. }
  510. dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
  511. }
  512. /* delete a region */
  513. static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
  514. {
  515. size_t addr;
  516. BoundEntry *e1;
  517. addr = (size_t)p;
  518. addr -= e->start;
  519. if (addr <= e->size) {
  520. /* region found is first one */
  521. e1 = e->next;
  522. if (e1 == NULL) {
  523. /* no more region: mark it empty */
  524. e->start = 0;
  525. e->size = empty_size;
  526. } else {
  527. /* copy next region in head */
  528. e->start = e1->start;
  529. e->size = e1->size;
  530. e->next = e1->next;
  531. bound_free_entry(e1);
  532. }
  533. } else {
  534. /* find the matching region */
  535. for(;;) {
  536. e1 = e;
  537. e = e->next;
  538. /* region not found: do nothing */
  539. if (e == NULL)
  540. break;
  541. addr = (size_t)p - e->start;
  542. if (addr <= e->size) {
  543. /* found: remove entry */
  544. e1->next = e->next;
  545. bound_free_entry(e);
  546. break;
  547. }
  548. }
  549. }
  550. }
  551. /* WARNING: 'p' must be the starting point of the region. */
  552. /* return non zero if error */
  553. int __bound_delete_region(void *p)
  554. {
  555. size_t start, end, addr, size, empty_size;
  556. BoundEntry *page, *e, *e2;
  557. size_t t1_start, t1_end, t2_start, t2_end, i;
  558. dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
  559. __bound_init();
  560. start = (size_t)p;
  561. t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
  562. t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  563. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
  564. /* find region size */
  565. page = __bound_t1[t1_start];
  566. e = (BoundEntry *)((char *)page + t2_start);
  567. addr = start - e->start;
  568. if (addr > e->size)
  569. e = __bound_find_region(e, p);
  570. /* test if invalid region */
  571. if (e->size == EMPTY_SIZE || (size_t)p != e->start)
  572. return -1;
  573. /* compute the size we put in invalid regions */
  574. if (e->is_invalid)
  575. empty_size = INVALID_SIZE;
  576. else
  577. empty_size = EMPTY_SIZE;
  578. size = e->size;
  579. end = start + size;
  580. /* now we can free each entry */
  581. t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
  582. t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  583. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
  584. delete_region(e, p, empty_size);
  585. if (t1_end == t1_start) {
  586. /* same ending page */
  587. e2 = (BoundEntry *)((char *)page + t2_end);
  588. if (e2 > e) {
  589. e++;
  590. for(;e<e2;e++) {
  591. e->start = 0;
  592. e->size = empty_size;
  593. }
  594. delete_region(e, p, empty_size);
  595. }
  596. } else {
  597. /* mark until end of page */
  598. e2 = page + BOUND_T2_SIZE;
  599. e++;
  600. for(;e<e2;e++) {
  601. e->start = 0;
  602. e->size = empty_size;
  603. }
  604. /* mark intermediate pages, if any */
  605. /* XXX: should free them */
  606. for(i=t1_start+1;i<t1_end;i++) {
  607. page = get_page(i);
  608. e2 = page + BOUND_T2_SIZE;
  609. for(e=page;e<e2;e++) {
  610. e->start = 0;
  611. e->size = empty_size;
  612. }
  613. }
  614. /* last page */
  615. page = get_page(t1_end);
  616. e2 = (BoundEntry *)((char *)page + t2_end);
  617. for(e=page;e<e2;e++) {
  618. e->start = 0;
  619. e->size = empty_size;
  620. }
  621. delete_region(e, p, empty_size);
  622. }
  623. dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
  624. return 0;
  625. }
  626. /* return the size of the region starting at p, or EMPTY_SIZE if non
  627. existent region. */
  628. static size_t get_region_size(void *p)
  629. {
  630. size_t addr = (size_t)p;
  631. BoundEntry *e;
  632. e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
  633. e = (BoundEntry *)((char *)e +
  634. ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
  635. ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
  636. addr -= e->start;
  637. if (addr > e->size)
  638. e = __bound_find_region(e, p);
  639. if (e->start != (size_t)p)
  640. return EMPTY_SIZE;
  641. return e->size;
  642. }
  643. /* patched memory functions */
  644. /* force compiler to perform stores coded up to this point */
  645. #define barrier() __asm__ __volatile__ ("": : : "memory")
  646. static void install_malloc_hooks(void)
  647. {
  648. #ifdef CONFIG_TCC_MALLOC_HOOKS
  649. saved_malloc_hook = __malloc_hook;
  650. saved_free_hook = __free_hook;
  651. saved_realloc_hook = __realloc_hook;
  652. saved_memalign_hook = __memalign_hook;
  653. __malloc_hook = __bound_malloc;
  654. __free_hook = __bound_free;
  655. __realloc_hook = __bound_realloc;
  656. __memalign_hook = __bound_memalign;
  657. barrier();
  658. #endif
  659. }
  660. static void restore_malloc_hooks(void)
  661. {
  662. #ifdef CONFIG_TCC_MALLOC_HOOKS
  663. __malloc_hook = saved_malloc_hook;
  664. __free_hook = saved_free_hook;
  665. __realloc_hook = saved_realloc_hook;
  666. __memalign_hook = saved_memalign_hook;
  667. barrier();
  668. #endif
  669. }
  670. static void *libc_malloc(size_t size)
  671. {
  672. void *ptr;
  673. restore_malloc_hooks();
  674. ptr = malloc(size);
  675. install_malloc_hooks();
  676. return ptr;
  677. }
  678. static void libc_free(void *ptr)
  679. {
  680. restore_malloc_hooks();
  681. free(ptr);
  682. install_malloc_hooks();
  683. }
  684. /* XXX: we should use a malloc which ensure that it is unlikely that
  685. two malloc'ed data have the same address if 'free' are made in
  686. between. */
  687. void *__bound_malloc(size_t size, const void *caller)
  688. {
  689. void *ptr;
  690. /* we allocate one more byte to ensure the regions will be
  691. separated by at least one byte. With the glibc malloc, it may
  692. be in fact not necessary */
  693. ptr = libc_malloc(size + 1);
  694. if (!ptr)
  695. return NULL;
  696. dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
  697. __FILE__, __FUNCTION__, ptr, (unsigned)size);
  698. __bound_new_region(ptr, size);
  699. return ptr;
  700. }
  701. void *__bound_memalign(size_t size, size_t align, const void *caller)
  702. {
  703. void *ptr;
  704. restore_malloc_hooks();
  705. #ifndef HAVE_MEMALIGN
  706. if (align > 4) {
  707. /* XXX: handle it ? */
  708. ptr = NULL;
  709. } else {
  710. /* we suppose that malloc aligns to at least four bytes */
  711. ptr = malloc(size + 1);
  712. }
  713. #else
  714. /* we allocate one more byte to ensure the regions will be
  715. separated by at least one byte. With the glibc malloc, it may
  716. be in fact not necessary */
  717. ptr = memalign(size + 1, align);
  718. #endif
  719. install_malloc_hooks();
  720. if (!ptr)
  721. return NULL;
  722. dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
  723. __FILE__, __FUNCTION__, ptr, (unsigned)size);
  724. __bound_new_region(ptr, size);
  725. return ptr;
  726. }
  727. void __bound_free(void *ptr, const void *caller)
  728. {
  729. if (ptr == NULL)
  730. return;
  731. if (__bound_delete_region(ptr) != 0)
  732. bound_error("freeing invalid region");
  733. libc_free(ptr);
  734. }
  735. void *__bound_realloc(void *ptr, size_t size, const void *caller)
  736. {
  737. void *ptr1;
  738. size_t old_size;
  739. if (size == 0) {
  740. __bound_free(ptr, caller);
  741. return NULL;
  742. } else {
  743. ptr1 = __bound_malloc(size, caller);
  744. if (ptr == NULL || ptr1 == NULL)
  745. return ptr1;
  746. old_size = get_region_size(ptr);
  747. if (old_size == EMPTY_SIZE)
  748. bound_error("realloc'ing invalid pointer");
  749. memcpy(ptr1, ptr, old_size);
  750. __bound_free(ptr, caller);
  751. return ptr1;
  752. }
  753. }
  754. #ifndef CONFIG_TCC_MALLOC_HOOKS
  755. void *__bound_calloc(size_t nmemb, size_t size)
  756. {
  757. void *ptr;
  758. size = size * nmemb;
  759. ptr = __bound_malloc(size, NULL);
  760. if (!ptr)
  761. return NULL;
  762. memset(ptr, 0, size);
  763. return ptr;
  764. }
  765. #endif
  766. #if 0
  767. static void bound_dump(void)
  768. {
  769. BoundEntry *page, *e;
  770. size_t i, j;
  771. fprintf(stderr, "region dump:\n");
  772. for(i=0;i<BOUND_T1_SIZE;i++) {
  773. page = __bound_t1[i];
  774. for(j=0;j<BOUND_T2_SIZE;j++) {
  775. e = page + j;
  776. /* do not print invalid or empty entries */
  777. if (e->size != EMPTY_SIZE && e->start != 0) {
  778. fprintf(stderr, "%08x:",
  779. (i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
  780. (j << BOUND_T3_BITS));
  781. do {
  782. fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size);
  783. e = e->next;
  784. } while (e != NULL);
  785. fprintf(stderr, "\n");
  786. }
  787. }
  788. }
  789. }
  790. #endif
  791. /* some useful checked functions */
  792. /* check that (p ... p + size - 1) lies inside 'p' region, if any */
  793. static void __bound_check(const void *p, size_t size)
  794. {
  795. if (size == 0)
  796. return;
  797. p = __bound_ptr_add((void *)p, size - 1);
  798. if (p == INVALID_POINTER)
  799. bound_error("invalid pointer");
  800. }
  801. void *__bound_memcpy(void *dst, const void *src, size_t size)
  802. {
  803. void* p;
  804. dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n",
  805. __FILE__, __FUNCTION__, dst, src, (unsigned)size);
  806. __bound_check(dst, size);
  807. __bound_check(src, size);
  808. /* check also region overlap */
  809. if (src >= dst && src < dst + size)
  810. bound_error("overlapping regions in memcpy()");
  811. p = memcpy(dst, src, size);
  812. dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p);
  813. return p;
  814. }
  815. void *__bound_memmove(void *dst, const void *src, size_t size)
  816. {
  817. __bound_check(dst, size);
  818. __bound_check(src, size);
  819. return memmove(dst, src, size);
  820. }
  821. void *__bound_memset(void *dst, int c, size_t size)
  822. {
  823. __bound_check(dst, size);
  824. return memset(dst, c, size);
  825. }
  826. /* XXX: could be optimized */
  827. int __bound_strlen(const char *s)
  828. {
  829. const char *p;
  830. size_t len;
  831. len = 0;
  832. for(;;) {
  833. p = __bound_ptr_indir1((char *)s, len);
  834. if (p == INVALID_POINTER)
  835. bound_error("bad pointer in strlen()");
  836. if (*p == '\0')
  837. break;
  838. len++;
  839. }
  840. return len;
  841. }
  842. char *__bound_strcpy(char *dst, const char *src)
  843. {
  844. size_t len;
  845. void *p;
  846. dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n",
  847. __FILE__, __FUNCTION__, dst, src);
  848. len = __bound_strlen(src);
  849. p = __bound_memcpy(dst, src, len + 1);
  850. dprintf(stderr, "%s %s: strcpy end, p = %p\n",
  851. __FILE__, __FUNCTION__, p);
  852. return p;
  853. }