ptr_chck.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
  3. *
  4. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  6. *
  7. * Permission is hereby granted to use or copy this program
  8. * for any purpose, provided the above notices are retained on all copies.
  9. * Permission to modify the code and to distribute modified code is granted,
  10. * provided the above notices are retained, and a notice that the code was
  11. * modified is included with the above copyright notice.
  12. */
  13. #include "private/gc_pmark.h"
  14. /*
  15. * These are checking routines calls to which could be inserted by a
  16. * preprocessor to validate C pointer arithmetic.
  17. */
  18. STATIC void GC_CALLBACK GC_default_same_obj_print_proc(void * p, void * q)
  19. {
  20. ABORT_ARG2("GC_same_obj test failed",
  21. ": %p and %p are not in the same object", p, q);
  22. }
  23. void (GC_CALLBACK *GC_same_obj_print_proc) (void *, void *)
  24. = GC_default_same_obj_print_proc;
  25. /* Check that p and q point to the same object. Call */
  26. /* *GC_same_obj_print_proc if they don't. */
  27. /* Returns the first argument. (Return value may be hard */
  28. /* to use due to typing issues. But if we had a suitable */
  29. /* preprocessor...) */
  30. /* Succeeds if neither p nor q points to the heap. */
  31. /* We assume this is performance critical. (It shouldn't */
  32. /* be called by production code, but this can easily make */
  33. /* debugging intolerably slow.) */
  34. GC_API void * GC_CALL GC_same_obj(void *p, void *q)
  35. {
  36. struct hblk *h;
  37. hdr *hhdr;
  38. ptr_t base, limit;
  39. word sz;
  40. if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
  41. hhdr = HDR((word)p);
  42. if (hhdr == 0) {
  43. if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
  44. && HDR((word)q) != 0) {
  45. goto fail;
  46. }
  47. return(p);
  48. }
  49. /* If it's a pointer to the middle of a large object, move it */
  50. /* to the beginning. */
  51. if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
  52. h = HBLKPTR(p) - (word)hhdr;
  53. hhdr = HDR(h);
  54. while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
  55. h = FORWARDED_ADDR(h, hhdr);
  56. hhdr = HDR(h);
  57. }
  58. limit = (ptr_t)h + hhdr -> hb_sz;
  59. if ((word)p >= (word)limit || (word)q >= (word)limit
  60. || (word)q < (word)h) {
  61. goto fail;
  62. }
  63. return(p);
  64. }
  65. sz = hhdr -> hb_sz;
  66. if (sz > MAXOBJBYTES) {
  67. base = (ptr_t)HBLKPTR(p);
  68. limit = base + sz;
  69. if ((word)p >= (word)limit) {
  70. goto fail;
  71. }
  72. } else {
  73. size_t offset;
  74. size_t pdispl = HBLKDISPL(p);
  75. offset = pdispl % sz;
  76. if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
  77. /* W/o this check, we might miss an error if */
  78. /* q points to the first object on a page, and */
  79. /* points just before the page. */
  80. base = (ptr_t)p - offset;
  81. limit = base + sz;
  82. }
  83. /* [base, limit) delimits the object containing p, if any. */
  84. /* If p is not inside a valid object, then either q is */
  85. /* also outside any valid object, or it is outside */
  86. /* [base, limit). */
  87. if ((word)q >= (word)limit || (word)q < (word)base) {
  88. goto fail;
  89. }
  90. return(p);
  91. fail:
  92. (*GC_same_obj_print_proc)((ptr_t)p, (ptr_t)q);
  93. return(p);
  94. }
  95. STATIC void GC_CALLBACK GC_default_is_valid_displacement_print_proc (void *p)
  96. {
  97. ABORT_ARG1("GC_is_valid_displacement test failed", ": %p not valid", p);
  98. }
  99. void (GC_CALLBACK *GC_is_valid_displacement_print_proc)(void *) =
  100. GC_default_is_valid_displacement_print_proc;
  101. /* Check that if p is a pointer to a heap page, then it points to */
  102. /* a valid displacement within a heap object. */
  103. /* Uninteresting with GC_all_interior_pointers. */
  104. /* Always returns its argument. */
  105. /* Note that we don't lock, since nothing relevant about the header */
  106. /* should change while we have a valid object pointer to the block. */
  107. GC_API void * GC_CALL GC_is_valid_displacement(void *p)
  108. {
  109. hdr *hhdr;
  110. word pdispl;
  111. word offset;
  112. struct hblk *h;
  113. word sz;
  114. if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
  115. hhdr = HDR((word)p);
  116. if (hhdr == 0) return(p);
  117. h = HBLKPTR(p);
  118. if (GC_all_interior_pointers) {
  119. while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
  120. h = FORWARDED_ADDR(h, hhdr);
  121. hhdr = HDR(h);
  122. }
  123. }
  124. if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
  125. goto fail;
  126. }
  127. sz = hhdr -> hb_sz;
  128. pdispl = HBLKDISPL(p);
  129. offset = pdispl % sz;
  130. if ((sz > MAXOBJBYTES && (word)p >= (word)h + sz)
  131. || !GC_valid_offsets[offset]
  132. || (word)p - offset + sz > (word)(h + 1)) {
  133. goto fail;
  134. }
  135. return(p);
  136. fail:
  137. (*GC_is_valid_displacement_print_proc)((ptr_t)p);
  138. return(p);
  139. }
  140. STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void * p)
  141. {
  142. ABORT_ARG1("GC_is_visible test failed", ": %p not GC-visible", p);
  143. }
  144. void (GC_CALLBACK *GC_is_visible_print_proc)(void * p) =
  145. GC_default_is_visible_print_proc;
  146. #ifndef THREADS
  147. /* Could p be a stack address? */
  148. STATIC GC_bool GC_on_stack(void *p)
  149. {
  150. # ifdef STACK_GROWS_DOWN
  151. if ((word)p >= (word)GC_approx_sp()
  152. && (word)p < (word)GC_stackbottom) {
  153. return(TRUE);
  154. }
  155. # else
  156. if ((word)p <= (word)GC_approx_sp()
  157. && (word)p > (word)GC_stackbottom) {
  158. return(TRUE);
  159. }
  160. # endif
  161. return(FALSE);
  162. }
  163. #endif
  164. /* Check that p is visible */
  165. /* to the collector as a possibly pointer containing location. */
  166. /* If it isn't, invoke *GC_is_visible_print_proc. */
  167. /* Returns the argument in all cases. May erroneously succeed */
  168. /* in hard cases. (This is intended for debugging use with */
  169. /* untyped allocations. The idea is that it should be possible, though */
  170. /* slow, to add such a call to all indirect pointer stores.) */
  171. /* Currently useless for the multi-threaded worlds. */
  172. GC_API void * GC_CALL GC_is_visible(void *p)
  173. {
  174. hdr *hhdr;
  175. if ((word)p & (ALIGNMENT - 1)) goto fail;
  176. if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
  177. # ifdef THREADS
  178. hhdr = HDR((word)p);
  179. if (hhdr != 0 && GC_base(p) == 0) {
  180. goto fail;
  181. } else {
  182. /* May be inside thread stack. We can't do much. */
  183. return(p);
  184. }
  185. # else
  186. /* Check stack first: */
  187. if (GC_on_stack(p)) return(p);
  188. hhdr = HDR((word)p);
  189. if (hhdr == 0) {
  190. if (GC_is_static_root(p)) return(p);
  191. /* Else do it again correctly: */
  192. # if defined(DYNAMIC_LOADING) || defined(MSWIN32) \
  193. || defined(MSWINCE) || defined(CYGWIN32) || defined(PCR)
  194. GC_register_dynamic_libraries();
  195. if (GC_is_static_root(p))
  196. return(p);
  197. # endif
  198. goto fail;
  199. } else {
  200. /* p points to the heap. */
  201. word descr;
  202. ptr_t base = (ptr_t)GC_base(p); /* Should be manually inlined? */
  203. if (base == 0) goto fail;
  204. if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
  205. descr = hhdr -> hb_descr;
  206. retry:
  207. switch(descr & GC_DS_TAGS) {
  208. case GC_DS_LENGTH:
  209. if ((word)p - (word)base > descr) goto fail;
  210. break;
  211. case GC_DS_BITMAP:
  212. if ((word)p - (word)base >= WORDS_TO_BYTES(BITMAP_BITS)
  213. || ((word)p & (sizeof(word) - 1))) goto fail;
  214. if (!(((word)1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
  215. & descr)) goto fail;
  216. break;
  217. case GC_DS_PROC:
  218. /* We could try to decipher this partially. */
  219. /* For now we just punt. */
  220. break;
  221. case GC_DS_PER_OBJECT:
  222. if ((signed_word)descr >= 0) {
  223. descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
  224. } else {
  225. ptr_t type_descr = *(ptr_t *)base;
  226. descr = *(word *)(type_descr
  227. - (descr - (word)(GC_DS_PER_OBJECT
  228. - GC_INDIR_PER_OBJ_BIAS)));
  229. }
  230. goto retry;
  231. }
  232. return(p);
  233. }
  234. # endif
  235. fail:
  236. (*GC_is_visible_print_proc)((ptr_t)p);
  237. return(p);
  238. }
  239. GC_API void * GC_CALL GC_pre_incr (void **p, ptrdiff_t how_much)
  240. {
  241. void * initial = *p;
  242. void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
  243. if (!GC_all_interior_pointers) {
  244. (void) GC_is_valid_displacement(result);
  245. }
  246. return (*p = result);
  247. }
  248. GC_API void * GC_CALL GC_post_incr (void **p, ptrdiff_t how_much)
  249. {
  250. void * initial = *p;
  251. void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
  252. if (!GC_all_interior_pointers) {
  253. (void) GC_is_valid_displacement(result);
  254. }
  255. *p = result;
  256. return(initial);
  257. }