📄 yamd.c
字号:
s = (addr )(b->block_addr + PGSZ); e = (addr )(b->user_addr); /* incomplete */#endif /* The end */ s = (b->user_addr + b->user_size); e = b->suffix_addr; badp = magic_check_range(s, e); if (badp) { handle_bad_magic(b, badp); magic_fill_range(s, e); }}static voidcheck_heap(void){ block *p; /* Optimization. */ if (check_front) return; /* Always nestled directly against a zapped page. */ if (default_alignment > 1) for_each_block_by_alignment(p, unaligned_blocks) check_block(p); for_each_block_by_alignment(p, aligned_blocks) check_block(p);}static void *lite_malloc(size_t nbytes){ block *b; void *p; NO_CATCH(); b = REAL(malloc)(sizeof(block)); p = REAL(malloc)(nbytes); OK_CATCH(); if (!b || !p) return NULL; /* FIXME: Not nice when memory low */ b->user_addr = b->block_addr = (addr)p; b->user_size = b->block_size = nbytes; b->who_alloced = BY_LITE; b->who_freed = BY_NONE; b->realloc_backlink = NULL; /* Should be all we need to keep everyone else away from this. */ insert_block(b); return p;}/* This is starting to get hairy. */static void *do_malloc(size_t nbytes, size_t alignment, addr orig_caller, unsigned by_who, block *backlink){ block *b; int nomem = 0; /* Might a goto actually be cleaner?? */ check_heap(); /* As long as we have control... */ if (nbytes > WAY_TOO_BIG) { log_event(LOG_ERR, "Ridiculous allocation"); log_detail(LOG_ERR, "At\n"); do_traceback(LOG_ERR, orig_caller); log_detail(LOG_ERR, "attempt to %s %u bytes, which is way too big\n", get_entry_name(by_who), nbytes); return NULL; } NO_CATCH(); b = REAL(malloc)(sizeof(block)); OK_CATCH(); if (!b) nomem = 1; else { size_t ca; /* controlling alignment, in bytes */ size_t user_piece_size; /* size of the piece not guarded */ addr user_piece_start; user_piece_size = round_up(nbytes, PGSZ); ca = round_up(alignment, PGSZ); /* 1 addded for the ending guard page */ b->block_size = user_piece_size + ca + PGSZ; b->block_addr = (addr)do_valloc(b->block_size); if (b->block_addr) { user_piece_start = round_up(b->block_addr + PGSZ, ca); b->suffix_addr = user_piece_start + user_piece_size; zap(b->block_addr, user_piece_start - b->block_addr); zap(b->suffix_addr, (b->block_addr + b->block_size) - b->suffix_addr); if (check_front) b->user_addr = user_piece_start; else { b->user_addr = (b->suffix_addr - nbytes) & ~(alignment - 1); magic_fill_range(b->user_addr + nbytes, b->suffix_addr); }#ifdef DEBUG assert(b->suffix_addr >= b->user_addr); assert((b->user_addr & (alignment - 1)) == 0); bzero((void *)b->user_addr, nbytes); /* make sure it's touchable */#endif } else /* no memory */ { nomem = 1; } } if (nomem) { NO_CATCH(); if (b) REAL(free)(b); OK_CATCH(); /* Should this be LOG_WARN? */ log_event(LOG_INFO, "Failed allocation"); log_detail(LOG_INFO, "Failed to %s %u bytes (aligned to %u) at\n", get_entry_name(by_who), nbytes, alignment); do_traceback(LOG_INFO, orig_caller); return NULL; } /* Okay, set it all up. */ b->user_size = nbytes; b->alignment = alignment; generate_traceback(b->where_alloced, orig_caller); b->who_alloced = by_who; b->who_freed = BY_NONE; b->realloc_backlink = backlink;#ifdef COMPLETE_MAGIC if (complete_magic) magic_fill_block(b);#endif insert_block(b); /* Lies, damn lies, and... */ user_currently_allocated += nbytes; if (user_currently_allocated > max_user_allocated) max_user_allocated = user_currently_allocated; user_allocated += nbytes; n_allocations++; internal_allocated += b->block_size; /* total size allocated */ internal_mapped += (b->suffix_addr - (b->user_addr & ~PAGEMASK)); if (internal_mapped > max_internal_mapped) max_internal_mapped = internal_mapped; if (nbytes == 0) { log_event(LOG_WARN, "Zero-byte allocation"); describe_block(LOG_WARN, b); } else { log_event(LOG_INFO, "Normal allocation of this block"); describe_block(LOG_INFO, b); } return (void *)b->user_addr;}WRAPPER_LINKAGE void *WRAP(malloc)(size_t n ){ void *p; MODE_VAR; if (SHOULD_NOT_CATCH) return REAL(malloc)(n); ENTER(); if (WAS_LITE_MODE) p = lite_malloc(n); else p = do_malloc(n, default_alignment, (addr)__builtin_return_address(0), BY_MALLOC, NULL); LEAVE(); return p;}static inline intlog_base_2(unsigned long x){ int i; i = -1; while (x != 0) { x >>= 1; i++; } return i;}#ifdef HAVE_MEMALIGNstatic void *lite_memalign(size_t alignment, size_t nbytes){ block *b; void *p; NO_CATCH(); b = REAL(malloc)(sizeof(block)); p = REAL(memalign)(alignment, nbytes); OK_CATCH(); if (!b || !p) return NULL; /* FIXME: Not nice when memory low */ b->user_addr = b->block_addr = (addr)p; b->user_size = b->block_size = nbytes; b->who_alloced = BY_LITE; b->who_freed = BY_NONE; b->realloc_backlink = NULL; /* Should be all we need to keep everyone else away from this. */ insert_block(b); return p;}WRAPPER_LINKAGEvoid *WRAP(memalign)(size_t alignment, size_t size ){ void *p; int t; MODE_VAR; if (SHOULD_NOT_CATCH) return REAL(memalign) (alignment, size); ENTER(); if (WAS_LITE_MODE) p = lite_memalign(alignment, size); else { /* Check alignment for sanity */ if (alignment > WAY_TOO_BIG) { log_event(LOG_ERR, "Ridiculous alignment"); log_detail(LOG_ERR, "At\n"); do_traceback(LOG_ERR, (addr)__builtin_return_address(0)); log_detail(LOG_ERR, "attempt to memalign with %u byte alignment, which is way too big\n", alignment); LEAVE(); return NULL; } t = log_base_2(alignment); if (t < 0 || alignment != (1UL << t)) { size_t new_alignment = 1UL << (t + 1); log_event(LOG_ERR, "Alignment not power of 2"); log_detail(LOG_ERR, "At\n"); do_traceback(LOG_ERR, (addr)__builtin_return_address(0)); log_detail(LOG_ERR, "Attempt to memalign with %u byte alignment, which is not a power of 2\n", alignment); log_detail(LOG_ERR, "Using alignment of %u instead\n", new_alignment); if (new_alignment > WAY_TOO_BIG) { log_detail(LOG_ERR, "Oops, that's too big, giving up.\n"); LEAVE(); return NULL; } alignment = new_alignment; } p = do_malloc(size, alignment, (addr)__builtin_return_address(0), BY_MEMALIGN, NULL); } LEAVE(); return p;}#endif/* KLUDGE: Returns block * */static block *block_to_free(void *user, addr orig_caller, unsigned by_who){ block *b; check_heap(); /* Got to do it sometime */ if (!user && by_who != BY_REALLOC) /* realloc(NULL, ...) is OK */ { log_event(LOG_WARN, "Free of null pointer"); log_detail(LOG_WARN, "At\n"); do_traceback(LOG_WARN, orig_caller); log_detail(LOG_WARN, "Attempt to %s null pointer\n", get_entry_name(by_who)); return NULL; } b = find_block_by_user_addr((addr)user); if (!b) { log_event(LOG_ERR, "Free of errnoneous pointer"); log_detail(LOG_ERR, "At\n"); do_traceback(LOG_ERR, orig_caller); log_detail(LOG_ERR, "Freeing erroneous pointer " POINTER_FORMAT "\n", user); describe_address(LOG_ERR, (addr)user); return NULL; } if (b->who_freed != BY_NONE) { log_event(LOG_ERR, "Multiple freeing"); log_detail(LOG_ERR, "At\n"); do_traceback(LOG_ERR, orig_caller); log_detail(LOG_ERR, "%s of pointer already freed\n", get_entry_name(by_who)); describe_block(LOG_ERR, b); return NULL; } return b;}static void do_free_block(block *b, addr orig_caller, unsigned by_who){ if (b->who_alloced == BY_LITE) { lite_free_block(b); return; } zap(b->block_addr, b->block_size); b->who_freed = by_who; if (by_who != BY_AUTO) generate_traceback(b->where_freed, orig_caller); /* We make sure that the traceback of an auto-freed block isn't used. */ user_currently_allocated -= b->user_size; internal_mapped += (b->suffix_addr - (b->user_addr & ~PAGEMASK)); log_event(LOG_INFO, "Normal deallocation of this block"); describe_block(LOG_INFO, b);}static voidlite_free_block(block *b){ b->who_freed = BY_LITE;#if 0 /* Enable this later */ if (b->who_alloced == BY_LITE) { NO_CATCH(); REAL(free)((void *)b->user_addr); OK_CATCH(); }#endif}static voidlite_free(void *p){ block *b;#ifdef DEBUG /* We don't expect any errors here, but just for paranoia... */ b = block_to_free(p, 0, BY_LITE);#else b = find_block_by_user_addr((addr)p);#endif if (b) lite_free_block(b);}WRAPPER_LINKAGEvoidWRAP(free) (void *p ){ MODE_VAR; block *b; if (SHOULD_NOT_CATCH) { REAL(free)(p); return; } ENTER(); if (WAS_LITE_MODE) lite_free(p); else if ((b = block_to_free(p, (addr)__builtin_return_address(0), BY_FREE)) != NULL) do_free_block(b, (addr)__builtin_return_address(0), BY_FREE); LEAVE();}static void *do_realloc(void *p, size_t s, addr orig_caller){ void *q; block *b; if (p) { b = block_to_free(p, orig_caller, BY_REALLOC); if (!b) b = BAD_POINTER; /* not NULL, since reallocing from NULL is not the same as reallocing from a bad pointer. */ } else { b = NULL; } q = do_malloc(s, default_alignment, orig_caller, BY_REALLOC, b); if (b && b != BAD_POINTER) { size_t ncpy; if (s < b->user_size) ncpy = s; else ncpy = b->user_size; memcpy(q, (void *)b->user_addr, ncpy); do_free_block(b, orig_caller, BY_REALLOC); } return q;}static void *lite_realloc(void *p, size_t s){ block *b; void *q; size_t ncpy;#ifdef DEBUG /* We don't expect any errors here, but just for paranoia... */ b = block_to_free(p, 0, BY_LITE);#else b = find_block_by_user_addr((addr)p);#endif if (!b) { /* Hmm. Not a good thing. */ return NULL; } q = lite_malloc(s); if (!q) { return NULL; } if (s < b->user_size) ncpy = s; else ncpy = b->user_size; memcpy(q, (void *)b->user_addr, ncpy); lite_free_block(b); return q;}WRAPPER_LINKAGEvoid *WRAP(realloc)(void *p, size_t s){ MODE_VAR; void *q; if (SHOULD_NOT_CATCH) return REAL(realloc)(p, s); ENTER(); if (WAS_LITE_MODE) q = lite_realloc(p, s); else q = do_realloc(p, s, (addr)__builtin_return_address(0)); LEAVE(); return q;}static voiddescribe_address(int level, addr a){ block *b; b = find_block_by_any_addr(a); if (b) { int ofs; log_detail(level, "Seems to be part of this block:\n"); describe_block(level, b); ofs = a - b->user_addr; log_detail(level, "Address in question is at offset %d", ofs); if (ofs >= 0 && ofs < (int)b->user_size) log_detail(level, " (in bounds)\n"); else log_detail(level, " (out of bounds)\n"); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -