bcheck.c 24 KB

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