/* * check_uuids_between_replicas -- (internal) check if uuids between internally * consistent adjacent replicas are consistent */ static int check_uuids_between_replicas(struct pool_set *set, struct poolset_health_status *set_hs) { for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip comparing inconsistent pairs of replicas */ if (!replica_is_replica_consistent(r, set_hs) || !replica_is_replica_consistent(r + 1, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_n = REP(set, r + 1); struct replica_health_status *rep_hs = REP(set_hs, r); struct replica_health_status *rep_n_hs = REP(set_hs, r + 1); /* check adjacent replica uuids for yet unbroken parts */ unsigned p = replica_find_unbroken_part(r, set_hs); unsigned p_n = replica_find_unbroken_part(r + 1, set_hs); /* if the first part is broken, cannot compare replica uuids */ if (p > 0) { rep_hs->flags |= IS_BROKEN; continue; } /* if the first part is broken, cannot compare replica uuids */ if (p_n > 0) { rep_n_hs->flags |= IS_BROKEN; continue; } /* check if replica uuids are consistent between replicas */ if (uuidcmp(HDR(rep_n, p_n)->prev_repl_uuid, HDR(rep, p)->uuid) || uuidcmp( HDR(rep, p)->next_repl_uuid, HDR(rep_n, p_n)->uuid)) { if (set->nreplicas == 1) { rep_hs->flags |= IS_INCONSISTENT; } else { if (replica_is_replica_broken(r, set_hs)) { rep_hs->flags |= IS_BROKEN; continue; } if (replica_is_replica_broken(r + 1, set_hs)) { rep_n_hs->flags |= IS_BROKEN; continue; } // two unbroken and internally consistent // adjacent replicas have different adjacent // replica uuids - mark one as inconsistent rep_n_hs->flags |= IS_INCONSISTENT; continue; } } } return 0; }
/* should change while we have a valid object pointer to the block. */ GC_API void * GC_CALL GC_is_valid_displacement(void *p) { hdr *hhdr; word pdispl; word offset; struct hblk *h; word sz; if (!GC_is_initialized) GC_init(); hhdr = HDR((word)p); if (hhdr == 0) return(p); h = HBLKPTR(p); if (GC_all_interior_pointers) { while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { h = FORWARDED_ADDR(h, hhdr); hhdr = HDR(h); } } if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { goto fail; } sz = hhdr -> hb_sz; pdispl = HBLKDISPL(p); offset = pdispl % sz; if ((sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) || !GC_valid_offsets[offset] || (ptr_t)p - offset + sz > (ptr_t)(h + 1)) { goto fail; } return(p); fail: (*GC_is_valid_displacement_print_proc)((ptr_t)p); return(p); }
/* * update_replicas_linkage -- (internal) update uuids linking replicas */ static int update_replicas_linkage(struct pool_set *set, unsigned repn) { LOG(3, "set %p, repn %u", set, repn); struct pool_replica *rep = REP(set, repn); struct pool_replica *prev_r = REPP(set, repn); struct pool_replica *next_r = REPN(set, repn); ASSERT(rep->nparts > 0); ASSERT(prev_r->nparts > 0); ASSERT(next_r->nparts > 0); /* set uuids in the current replica */ for (unsigned p = 0; p < rep->nhdrs; ++p) { struct pool_hdr *hdrp = HDR(rep, p); memcpy(hdrp->prev_repl_uuid, PART(prev_r, 0).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_repl_uuid, PART(next_r, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 1, POOL_HDR_CSUM_END_OFF); /* store pool's header */ util_persist(PART(rep, p).is_dev_dax, hdrp, sizeof(*hdrp)); } /* set uuids in the previous replica */ for (unsigned p = 0; p < prev_r->nhdrs; ++p) { struct pool_hdr *prev_hdrp = HDR(prev_r, p); memcpy(prev_hdrp->next_repl_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(prev_hdrp, sizeof(*prev_hdrp), &prev_hdrp->checksum, 1, POOL_HDR_CSUM_END_OFF); /* store pool's header */ util_persist(PART(prev_r, p).is_dev_dax, prev_hdrp, sizeof(*prev_hdrp)); } /* set uuids in the next replica */ for (unsigned p = 0; p < next_r->nhdrs; ++p) { struct pool_hdr *next_hdrp = HDR(next_r, p); memcpy(next_hdrp->prev_repl_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(next_hdrp, sizeof(*next_hdrp), &next_hdrp->checksum, 1, POOL_HDR_CSUM_END_OFF); /* store pool's header */ util_persist(PART(next_r, p).is_dev_dax, next_hdrp, sizeof(*next_hdrp)); } return 0; }
/* * fill_struct_broken_part_uuids -- (internal) set part uuids in pool_set * structure */ static int fill_struct_broken_part_uuids(struct pool_set *set, unsigned repn, struct poolset_health_status *set_hs, unsigned flags) { struct pool_replica *rep = REP(set, repn); struct pool_hdr *hdrp; for (unsigned p = 0; p < rep->nparts; ++p) { /* skip unbroken parts */ if (!replica_is_part_broken(repn, p, set_hs)) continue; /* check if part was damaged or was added by transform */ if (replica_is_poolset_transformed(flags)) { /* generate new uuid for this part */ if (util_uuid_generate(rep->part[p].uuid) < 0) { ERR("cannot generate pool set part UUID"); errno = EINVAL; return -1; } continue; } if (!replica_is_part_broken(repn, p + 1, set_hs)) { /* try to get part uuid from the next part */ hdrp = HDR(rep, p + 1); memcpy(rep->part[p].uuid, hdrp->prev_part_uuid, POOL_HDR_UUID_LEN); } else if (!replica_is_part_broken(repn, p - 1, set_hs)) { /* try to get part uuid from the previous part */ hdrp = HDR(rep, p - 1); memcpy(rep->part[p].uuid, hdrp->next_part_uuid, POOL_HDR_UUID_LEN); } else if (p == 0 && replica_find_unbroken_part(repn + 1, set_hs) == 0) { /* try to get part uuid from the next replica */ hdrp = HDR(REP(set, repn + 1), 0); memcpy(rep->part[p].uuid, hdrp->prev_repl_uuid, POOL_HDR_UUID_LEN); } else if (p == 0 && replica_find_unbroken_part(repn - 1, set_hs) == 0) { /* try to get part uuid from the previous replica */ hdrp = HDR(REP(set, repn - 1), 0); memcpy(rep->part[p].uuid, hdrp->next_repl_uuid, POOL_HDR_UUID_LEN); } else { /* generate new uuid for this part */ if (util_uuid_generate(rep->part[p].uuid) < 0) { ERR("cannot generate pool set part UUID"); errno = EINVAL; return -1; } } } return 0; }
/* * update_replicas_linkage -- (internal) update uuids linking replicas */ static int update_replicas_linkage(struct pool_set *set, unsigned repn) { struct pool_replica *rep = REP(set, repn); struct pool_replica *prev_r = REP(set, repn - 1); struct pool_replica *next_r = REP(set, repn + 1); /* set uuids in the current replica */ for (unsigned p = 0; p < rep->nparts; ++p) { struct pool_hdr *hdrp = HDR(rep, p); memcpy(hdrp->prev_repl_uuid, PART(prev_r, 0).uuid, POOL_HDR_UUID_LEN); memcpy(hdrp->next_repl_uuid, PART(next_r, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 1); /* store pool's header */ pmem_msync(hdrp, sizeof(*hdrp)); } /* set uuids in the previous replica */ for (unsigned p = 0; p < prev_r->nparts; ++p) { struct pool_hdr *prev_hdrp = HDR(prev_r, p); memcpy(prev_hdrp->next_repl_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(prev_hdrp, sizeof(*prev_hdrp), &prev_hdrp->checksum, 1); /* store pool's header */ pmem_msync(prev_hdrp, sizeof(*prev_hdrp)); } /* set uuids in the next replica */ for (unsigned p = 0; p < next_r->nparts; ++p) { struct pool_hdr *next_hdrp = HDR(next_r, p); memcpy(next_hdrp->prev_repl_uuid, PART(rep, 0).uuid, POOL_HDR_UUID_LEN); util_checksum(next_hdrp, sizeof(*next_hdrp), &next_hdrp->checksum, 1); /* store pool's header */ pmem_msync(next_hdrp, sizeof(*next_hdrp)); } return 0; }
/* * create_headers_for_broken_parts -- (internal) create headers for all new * parts created in place of the broken ones */ static int create_headers_for_broken_parts(struct pool_set *set, unsigned src_replica, struct poolset_health_status *set_hs) { struct pool_hdr *src_hdr = HDR(REP(set, src_replica), 0); for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; for (unsigned p = 0; p < set_hs->replica[r]->nparts; p++) { /* skip unbroken parts */ if (!replica_is_part_broken(r, p, set_hs)) continue; if (util_header_create(set, r, p, src_hdr->signature, src_hdr->major, src_hdr->compat_features, src_hdr->incompat_features, src_hdr->ro_compat_features, NULL, NULL, NULL) != 0) { LOG(1, "part headers create failed for" " replica %u part %u", r, p); errno = EINVAL; return -1; } } } return 0; }
void GC_enumerate_block(struct hblk *h, enumerate_data * ed) { register hdr * hhdr; register int sz; ptr_t p; ptr_t lim; word descr; # if !defined(CPPCHECK) # error This code was updated without testing. # error and its precursor was clearly broken. # endif hhdr = HDR(h); descr = hhdr -> hb_descr; sz = hhdr -> hb_sz; if (descr != 0 && ed -> ed_pointerfree || descr == 0 && !(ed -> ed_pointerfree)) return; lim = (ptr_t)(h+1) - sz; p = (ptr_t)h; do { if (PCR_ERes_IsErr(ed -> ed_fail_code)) return; ed -> ed_fail_code = (*(ed -> ed_proc))(p, sz, ed -> ed_client_data); p+= sz; } while ((word)p <= (word)lim); }
/*ARGSUSED*/ void GC_check_heap_block(struct hblk *hbp, word dummy) { struct hblkhdr * hhdr = HDR(hbp); size_t sz = hhdr -> hb_sz; size_t bit_no; char *p, *plim; p = hbp->hb_body; bit_no = 0; if (sz > MAXOBJBYTES) { plim = p; } else { plim = hbp->hb_body + HBLKSIZE - sz; } /* go through all words in block */ while( p <= plim ) { if( mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) { ptr_t clobbered = GC_check_annotated_obj((oh *)p); if (clobbered != 0) GC_add_smashed(clobbered); } bit_no += MARK_BIT_OFFSET(sz); p += sz; } }
/* * check_shutdown_state -- (internal) check if replica has * healthy shutdown_state */ static int check_shutdown_state(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); for (unsigned r = 0; r < set->nreplicas; ++r) {\ struct pool_replica *rep = set->replica[r]; struct replica_health_status *rep_hs = set_hs->replica[r]; struct pool_hdr *hdrp = HDR(rep, 0); if (rep->remote) continue; if (hdrp == NULL) { /* cannot verify shutdown state */ rep_hs->flags |= IS_BROKEN; continue; } struct shutdown_state curr_sds; shutdown_state_init(&curr_sds, NULL); for (unsigned p = 0; p < rep->nparts; ++p) { shutdown_state_add_part(&curr_sds, PART(rep, p).path, NULL); } /* make a copy of sds as we shouldn't modify a pool */ struct shutdown_state pool_sds = hdrp->sds; if (shutdown_state_check(&curr_sds, &pool_sds, NULL)) rep_hs->flags |= IS_BROKEN; } return 0; }
/* * create_headers_for_broken_parts -- (internal) create headers for all new * parts created in place of the broken ones */ static int create_headers_for_broken_parts(struct pool_set *set, unsigned src_replica, struct poolset_health_status *set_hs) { LOG(3, "set %p, src_replica %u, set_hs %p", set, src_replica, set_hs); struct pool_hdr *src_hdr = HDR(REP(set, src_replica), 0); for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken replicas */ if (!replica_is_replica_broken(r, set_hs)) continue; for (unsigned p = 0; p < set_hs->replica[r]->nhdrs; p++) { /* skip unbroken parts */ if (!replica_is_part_broken(r, p, set_hs)) continue; struct pool_attr attr; util_pool_hdr2attr(&attr, src_hdr); if (util_header_create(set, r, p, &attr, 0) != 0) { LOG(1, "part headers create failed for" " replica %u part %u", r, p); errno = EINVAL; return -1; } } } return 0; }
/* * check_checksums -- (internal) check if checksums are correct for parts in * a given replica */ static int check_checksums(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); for (unsigned r = 0; r < set->nreplicas; ++r) { struct pool_replica *rep = REP(set, r); struct replica_health_status *rep_hs = REP(set_hs, r); if (rep->remote) continue; for (unsigned p = 0; p < rep->nparts; ++p) { /* skip broken parts */ if (replica_is_part_broken(r, p, set_hs)) continue; /* check part's checksum */ LOG(4, "checking checksum for part %u, replica %u", p, r); struct pool_hdr *hdrp = HDR(rep, p); if (!util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0)) {; ERR("invalid checksum of pool header"); rep_hs->part[p] |= IS_BROKEN; } else if (util_is_zeroed(hdrp, sizeof(*hdrp))) { rep_hs->part[p] |= IS_BROKEN; } } } return 0; }
GC_INNER GC_bool GC_check_leaked(ptr_t base) { size_t i; size_t obj_sz; word *p; if ( # if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) (*(word *)base & 1) != 0 && # endif GC_has_other_debug_info(base) >= 0) return TRUE; /* object has leaked */ /* Validate freed object's content. */ p = (word *)(base + sizeof(oh)); obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh)); for (i = 0; i < obj_sz; ++i) if (p[i] != GC_FREED_MEM_MARKER) { GC_set_mark_bit(base); /* do not reclaim it in this cycle */ GC_add_smashed((ptr_t)(&p[i])); /* alter-after-free detected */ break; /* don't report any other smashed locations in the object */ } return FALSE; /* GC_debug_free() has been called */ }
/* Clear both lists. */ GC_INNER void GC_print_all_errors(void) { static GC_bool printing_errors = FALSE; unsigned i; DCL_LOCK_STATE; LOCK(); if (printing_errors) { UNLOCK(); return; } printing_errors = TRUE; UNLOCK(); if (GC_debugging_started) GC_print_all_smashed(); for (i = 0; i < GC_n_leaked; ++i) { ptr_t p = GC_leaked[i]; if (HDR(p) -> hb_obj_kind == PTRFREE) { GC_err_printf("Leaked atomic object at "); } else { GC_err_printf("Leaked composite object at "); } GC_print_heap_obj(p); GC_err_printf("\n"); GC_free(p); GC_leaked[i] = 0; } GC_n_leaked = 0; printing_errors = FALSE; }
/* * check_poolset_uuids -- (internal) check if poolset_uuid fields are consistent * among all internally consistent replicas */ static int check_poolset_uuids(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); unsigned r_h = replica_find_healthy_replica(set_hs); if (r_h == UNDEF_REPLICA) { ERR("no healthy replica. Cannot synchronize."); return -1; } uuid_t poolset_uuid; memcpy(poolset_uuid, HDR(REP(set, r_h), 0)->poolset_uuid, POOL_HDR_UUID_LEN); for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip inconsistent replicas */ if (!replica_is_replica_consistent(r, set_hs) || r == r_h) continue; if (check_replica_poolset_uuids(set, r, poolset_uuid, set_hs)) { ERR("inconsistent poolset uuids between replicas %u and" " %u; cannot synchronize", r_h, r); return -1; } } return 0; }
void * GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS) { void * base = GC_base(p); ptr_t clobbered; void * result; size_t copy_sz = lb; size_t old_sz; hdr * hhdr; if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i)); if (base == 0) { GC_err_printf("Attempt to reallocate invalid pointer %p\n", p); ABORT("realloc(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_realloc called on pointer %p wo debugging info\n", p); return(GC_realloc(p, lb)); } hhdr = HDR(base); switch (hhdr -> hb_obj_kind) { # ifdef STUBBORN_ALLOC case STUBBORN: result = GC_debug_malloc_stubborn(lb, OPT_RA s, i); break; # endif case NORMAL: result = GC_debug_malloc(lb, OPT_RA s, i); break; case PTRFREE: result = GC_debug_malloc_atomic(lb, OPT_RA s, i); break; case UNCOLLECTABLE: result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i); break; # ifdef ATOMIC_UNCOLLECTABLE case AUNCOLLECTABLE: result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i); break; # endif default: GC_err_printf("GC_debug_realloc: encountered bad kind\n"); ABORT("bad kind"); } # ifdef SHORT_DBG_HDRS old_sz = GC_size(base) - sizeof(oh); # else clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { GC_err_printf("GC_debug_realloc: found smashed location at "); GC_print_smashed_obj(p, clobbered); } old_sz = ((oh *)base) -> oh_sz; # endif if (old_sz < copy_sz) copy_sz = old_sz; if (result == 0) return(0); BCOPY(p, result, copy_sz); GC_debug_free(p); return(result); }
/* * check_replica_poolset_uuids - (internal) check if poolset_uuid fields are * consistent among all parts of a replica; * the replica is initially considered as * consistent */ static int check_replica_poolset_uuids(struct pool_set *set, unsigned repn, uuid_t poolset_uuid, struct poolset_health_status *set_hs) { LOG(3, "set %p, repn %u, poolset_uuid %p, set_hs %p", set, repn, poolset_uuid, set_hs); struct pool_replica *rep = REP(set, repn); for (unsigned p = 0; p < rep->nhdrs; ++p) { /* skip broken parts */ if (replica_is_part_broken(repn, p, set_hs)) continue; if (uuidcmp(HDR(rep, p)->poolset_uuid, poolset_uuid)) { /* * two internally consistent replicas have * different poolset_uuid */ return -1; } else { /* * it is sufficient to check only one part * from internally consistent replica */ break; } } return 0; }
/* overflow is handled by the caller, and is not a disaster. */ GC_API void GC_normal_finalize_mark_proc(ptr_t p) { hdr * hhdr = HDR(p); PUSH_OBJ(p, hhdr, GC_mark_stack_top, &(GC_mark_stack[GC_mark_stack_size])); }
GC_INNER void GC_free_inner(void * p) { struct hblk *h; hdr *hhdr; size_t sz; /* bytes */ size_t ngranules; /* sz in granules */ void ** flh; int knd; struct obj_kind * ok; h = HBLKPTR(p); hhdr = HDR(h); knd = hhdr -> hb_obj_kind; sz = hhdr -> hb_sz; ngranules = BYTES_TO_GRANULES(sz); ok = &GC_obj_kinds[knd]; if (ngranules <= MAXOBJGRANULES) { GC_bytes_freed += sz; if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz; if (ok -> ok_init) { BZERO((word *)p + 1, sz-sizeof(word)); } flh = &(ok -> ok_freelist[ngranules]); obj_link(p) = *flh; *flh = (ptr_t)p; } else { size_t nblocks = OBJ_SZ_TO_BLOCKS(sz); GC_bytes_freed += sz; if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz; if (nblocks > 1) { GC_large_allocd_bytes -= nblocks * HBLKSIZE; } GC_freehblk(h); } }
/* Explicitly deallocate an object p. */ GC_API void GC_CALL GC_free(void * p) { struct hblk *h; hdr *hhdr; size_t sz; /* In bytes */ size_t ngranules; /* sz in granules */ void **flh; int knd; struct obj_kind * ok; DCL_LOCK_STATE; if (p == 0) return; /* Required by ANSI. It's not my fault ... */ # ifdef LOG_ALLOCS GC_log_printf("GC_free(%p) after GC #%lu\n", p, (unsigned long)GC_gc_no); # endif h = HBLKPTR(p); hhdr = HDR(h); # if defined(REDIRECT_MALLOC) && \ (defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \ || defined(MSWIN32)) /* For Solaris, we have to redirect malloc calls during */ /* initialization. For the others, this seems to happen */ /* implicitly. */ /* Don't try to deallocate that memory. */ if (0 == hhdr) return; # endif GC_ASSERT(GC_base(p) == p); sz = hhdr -> hb_sz; ngranules = BYTES_TO_GRANULES(sz); knd = hhdr -> hb_obj_kind; ok = &GC_obj_kinds[knd]; if (EXPECT(ngranules <= MAXOBJGRANULES, TRUE)) { LOCK(); GC_bytes_freed += sz; if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz; /* Its unnecessary to clear the mark bit. If the */ /* object is reallocated, it doesn't matter. O.w. the */ /* collector will do it, since it's on a free list. */ if (ok -> ok_init) { BZERO((word *)p + 1, sz-sizeof(word)); } flh = &(ok -> ok_freelist[ngranules]); obj_link(p) = *flh; *flh = (ptr_t)p; UNLOCK(); } else { size_t nblocks = OBJ_SZ_TO_BLOCKS(sz); LOCK(); GC_bytes_freed += sz; if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz; if (nblocks > 1) { GC_large_allocd_bytes -= nblocks * HBLKSIZE; } GC_freehblk(h); UNLOCK(); } }
STATIC void GC_update_check_page(struct hblk *h, int index) { page_entry *pe = GC_sums + index; hdr * hhdr = HDR(h); struct hblk *b; if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed"); pe -> old_sum = pe -> new_sum; pe -> new_sum = GC_checksum(h); # if !defined(MSWIN32) && !defined(MSWINCE) if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) { GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", h); } # endif if (GC_page_was_dirty(h)) { GC_n_dirty++; } else { GC_n_clean++; } b = h; while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) { b -= (word)hhdr; hhdr = HDR(b); } if (pe -> new_valid && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */ && pe -> old_sum != pe -> new_sum) { if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) { GC_bool was_faulted = GC_was_faulted(h); /* Set breakpoint here */GC_n_dirty_errors++; if (was_faulted) GC_n_faulted_dirty_errors++; } # ifdef STUBBORN_ALLOC if (!HBLK_IS_FREE(hhdr) && hhdr -> hb_obj_kind == STUBBORN && !GC_page_was_changed(h) && !GC_on_free_list(h)) { /* if GC_on_free_list(h) then reclaim may have touched it */ /* without any allocations taking place. */ /* Set breakpoint here */GC_n_changed_errors++; } # endif } pe -> new_valid = TRUE; pe -> block = h + OFFSET; }
int parse_help(aClient *sptr, char *name, char *help) { ConfigItem_help *helpitem; aMotd *text; if (BadPtr(help)) { helpitem = Find_Help(NULL); if (!helpitem) return 1; SND(" -"); HDR(" ***** UnrealIRCd Help System *****"); SND(" -"); text = helpitem->text; while (text) { SND(text->line); text = text->next; } SND(" -"); return 1; } helpitem = Find_Help(help); if (!helpitem) { SND(" -"); HDR(" ***** No Help Available *****"); SND(" -"); SND(" We're sorry, we don't have help available for the command you requested."); SND(" -"); sendto_one(sptr,":%s 292 %s : ***** Go to %s if you have any further questions *****", me.name, sptr->name, helpchan); SND(" -"); return 0; } text = helpitem->text; SND(" -"); sendto_one(sptr,":%s 290 %s :***** %s *****", me.name, sptr->name, helpitem->command); SND(" -"); while (text) { SND(text->line); text = text->next; } SND(" -"); return 1; }
GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS) { void * base; void * result; hdr * hhdr; if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i)); base = GC_base(p); if (base == 0) { GC_err_printf("Attempt to reallocate invalid pointer %p\n", p); ABORT("Invalid pointer passed to realloc()"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_realloc called on pointer %p w/o debugging info\n", p); return(GC_realloc(p, lb)); } hhdr = HDR(base); switch (hhdr -> hb_obj_kind) { # ifdef STUBBORN_ALLOC case STUBBORN: result = GC_debug_malloc_stubborn(lb, OPT_RA s, i); break; # endif case NORMAL: result = GC_debug_malloc(lb, OPT_RA s, i); break; case PTRFREE: result = GC_debug_malloc_atomic(lb, OPT_RA s, i); break; case UNCOLLECTABLE: result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i); break; # ifdef ATOMIC_UNCOLLECTABLE case AUNCOLLECTABLE: result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i); break; # endif default: result = NULL; /* initialized to prevent warning. */ GC_err_printf("GC_debug_realloc: encountered bad kind\n"); ABORT("Bad kind"); } if (result != NULL) { size_t old_sz; # ifdef SHORT_DBG_HDRS old_sz = GC_size(base) - sizeof(oh); # else old_sz = ((oh *)base) -> oh_sz; # endif BCOPY(p, result, old_sz < lb ? old_sz : lb); GC_debug_free(p); } return(result); }
GC_API void GC_CALL GC_debug_free(void * p) { ptr_t base; if (0 == p) return; base = GC_base(p); if (base == 0) { GC_err_printf("Attempt to free invalid pointer %p\n", p); ABORT("Invalid pointer passed to free()"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_free called on pointer %p w/o debugging info\n", p); } else { # ifndef SHORT_DBG_HDRS ptr_t clobbered = GC_check_annotated_obj((oh *)base); word sz = GC_size(base); if (clobbered != 0) { GC_have_errors = TRUE; if (((oh *)base) -> oh_sz == sz) { GC_print_smashed_obj( "GC_debug_free: found previously deallocated (?) object at", p, clobbered); return; /* ignore double free */ } else { GC_print_smashed_obj("GC_debug_free: found smashed location at", p, clobbered); } } /* Invalidate size (mark the object as deallocated) */ ((oh *)base) -> oh_sz = sz; # endif /* SHORT_DBG_HDRS */ } if (GC_find_leak # ifndef SHORT_DBG_HDRS && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free) # endif ) { GC_free(base); } else { hdr * hhdr = HDR(p); if (hhdr -> hb_obj_kind == UNCOLLECTABLE # ifdef ATOMIC_UNCOLLECTABLE || hhdr -> hb_obj_kind == AUNCOLLECTABLE # endif ) { GC_free(base); } else { size_t i; size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh)); for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = GC_FREED_MEM_MARKER; GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz)); } } /* !GC_find_leak */ }
/*ARGSUSED*/ STATIC void GC_add_block(struct hblk *h, word dummy) { hdr * hhdr = HDR(h); size_t bytes = hhdr -> hb_sz; bytes += HBLKSIZE-1; bytes &= ~(HBLKSIZE-1); GC_bytes_in_used_blocks += bytes; }
GC_INNER void GC_default_print_heap_obj_proc(ptr_t p) { ptr_t base = (ptr_t)GC_base(p); int kind = HDR(base)->hb_obj_kind; GC_err_printf("object at %p of appr. %lu bytes (%s)\n", (void *)base, (unsigned long)GC_size(base), kind == PTRFREE ? "atomic" : IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite"); }
void GC_debug_free(void * p) { ptr_t base; ptr_t clobbered; if (0 == p) return; base = GC_base(p); if (base == 0) { GC_err_printf("Attempt to free invalid pointer %p\n", p); ABORT("free(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_free called on pointer %p wo debugging info\n", p); } else { # ifndef SHORT_DBG_HDRS clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { if (((oh *)base) -> oh_sz == GC_size(base)) { GC_err_printf( "GC_debug_free: found previously deallocated (?) object at "); } else { GC_err_printf("GC_debug_free: found smashed location at "); } GC_print_smashed_obj(p, clobbered); } /* Invalidate size */ ((oh *)base) -> oh_sz = GC_size(base); # endif /* SHORT_DBG_HDRS */ } if (GC_find_leak) { GC_free(base); } else { hdr * hhdr = HDR(p); GC_bool uncollectable = FALSE; if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { uncollectable = TRUE; } # ifdef ATOMIC_UNCOLLECTABLE if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { uncollectable = TRUE; } # endif if (uncollectable) { GC_free(base); } else { size_t i; size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh)); for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef; GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz)); } } /* !GC_find_leak */ }
/* * check_replica_sizes -- (internal) check if all replicas are large * enough to hold data from a healthy replica */ static int check_replica_sizes(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); ssize_t pool_size = -1; for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip broken replicas */ if (!replica_is_replica_healthy(r, set_hs)) continue; /* get the size of a pool in the replica */ ssize_t replica_pool_size; if (REP(set, r)->remote) /* XXX: no way to get the size of a remote pool yet */ replica_pool_size = (ssize_t)set->poolsize; else replica_pool_size = replica_get_pool_size(set, r); if (replica_pool_size < 0) { LOG(1, "getting pool size from replica %u failed", r); set_hs->replica[r]->flags |= IS_BROKEN; continue; } /* check if the pool is bigger than minimum size */ enum pool_type type = pool_hdr_get_type(HDR(REP(set, r), 0)); if ((size_t)replica_pool_size < pool_get_min_size(type)) { LOG(1, "pool size from replica %u is smaller than the minimum size allowed for the pool", r); set_hs->replica[r]->flags |= IS_BROKEN; continue; } /* check if each replica is big enough to hold the pool data */ if (set->poolsize < (size_t)replica_pool_size) { ERR( "some replicas are too small to hold synchronized data"); return -1; } if (pool_size < 0) { pool_size = replica_pool_size; continue; } /* check if pools in all healthy replicas are of equal size */ if (pool_size != replica_pool_size) { ERR("pool sizes from different replicas differ"); return -1; } } return 0; }
/* Clear both lists. Called without the allocation lock held. */ GC_INNER void GC_print_all_errors(void) { static GC_bool printing_errors = FALSE; GC_bool have_errors; unsigned i, n_leaked; ptr_t leaked[MAX_LEAKED]; DCL_LOCK_STATE; LOCK(); if (printing_errors) { UNLOCK(); return; } have_errors = GC_have_errors; printing_errors = TRUE; n_leaked = GC_n_leaked; GC_ASSERT(n_leaked <= MAX_LEAKED); BCOPY(GC_leaked, leaked, n_leaked * sizeof(ptr_t)); GC_n_leaked = 0; BZERO(GC_leaked, n_leaked * sizeof(ptr_t)); UNLOCK(); if (GC_debugging_started) { GC_print_all_smashed(); } else { have_errors = FALSE; } for (i = 0; i < n_leaked; i++) { ptr_t p = leaked[i]; if (HDR(p) -> hb_obj_kind == PTRFREE) { GC_err_printf("Leaked atomic object at "); } else { GC_err_printf("Leaked composite object at "); } GC_print_heap_obj(p); GC_err_printf("\n"); GC_free(p); have_errors = TRUE; } if (have_errors # ifndef GC_ABORT_ON_LEAK && GETENV("GC_ABORT_ON_LEAK") != NULL # endif ) { ABORT("Leaked or smashed objects encountered"); } LOCK(); printing_errors = FALSE; UNLOCK(); }
/* the appropriate free list. */ STATIC GC_bool GC_on_free_list(struct hblk *h) { hdr * hhdr = HDR(h); size_t sz = BYTES_TO_WORDS(hhdr -> hb_sz); ptr_t p; if (sz > MAXOBJWORDS) return(FALSE); for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) { if (HBLKPTR(p) == h) return(TRUE); } return(FALSE); }
/* Allocate lb bytes of pointerful, traced, but not collectable data */ GC_API void * GC_CALL GC_malloc_uncollectable(size_t lb) { void *op; void **opp; size_t lg; DCL_LOCK_STATE; if( SMALL_OBJ(lb) ) { if (EXTRA_BYTES != 0 && lb != 0) lb--; /* We don't need the extra byte, since this won't be */ /* collected anyway. */ lg = GC_size_map[lb]; opp = &(GC_uobjfreelist[lg]); LOCK(); if( (op = *opp) != 0 ) { *opp = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); /* Mark bit ws already set on free list. It will be */ /* cleared only temporarily during a collection, as a */ /* result of the normal free list mark bit clearing. */ GC_non_gc_bytes += GRANULES_TO_BYTES(lg); UNLOCK(); } else { UNLOCK(); op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE); /* For small objects, the free lists are completely marked. */ } GC_ASSERT(0 == op || GC_is_marked(op)); return((void *) op); } else { hdr * hhdr; op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE); if (0 == op) return(0); GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */ hhdr = HDR(op); /* We don't need the lock here, since we have an undisguised */ /* pointer. We do need to hold the lock while we adjust */ /* mark bits. */ LOCK(); set_mark_bit_from_hdr(hhdr, 0); /* Only object. */ # ifndef THREADS GC_ASSERT(hhdr -> hb_n_marks == 0); /* This is not guaranteed in the multi-threaded case */ /* because the counter could be updated before locking. */ # endif hhdr -> hb_n_marks = 1; UNLOCK(); return((void *) op); } }