// Forward declarations
static void mc_record_address_error ( ThreadId tid, Addr a,
Int size, Bool isWrite );
-static void mc_record_core_mem_error ( ThreadId tid, Bool isUnaddr, Char* s );
-static void mc_record_param_error ( ThreadId tid, Addr a, Bool isReg,
- Bool isUnaddr, Char* msg );
+static void mc_record_core_mem_error ( ThreadId tid, Bool isAddrErr, Char* s );
+static void mc_record_regparam_error ( ThreadId tid, Char* msg );
+static void mc_record_memparam_error ( ThreadId tid, Addr a,
+ Bool isAddrErr, Char* msg );
static void mc_record_jump_error ( ThreadId tid, Addr a );
static
tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
/* Dump vbytes in memory, iterating from least to most significant
- byte. At the same time establish addressibility of the
- location. */
+ byte. At the same time establish addressibility of the location. */
for (i = 0; i < szB; i++) {
PROF_EVENT(36, "mc_STOREVn_slow(loop)");
ai = a + byte_offset_w(szB, bigendian, i);
if (!ok) {
switch (part) {
case Vg_CoreSysCall:
- mc_record_param_error ( tid, bad_addr, /*isReg*/False,
- /*isUnaddr*/True, s );
+ mc_record_memparam_error ( tid, bad_addr, /*isAddrErr*/True, s );
break;
case Vg_CoreSignal:
- mc_record_core_mem_error( tid, /*isUnaddr*/True, s );
+ mc_record_core_mem_error( tid, /*isAddrErr*/True, s );
break;
default:
MC_ReadResult res = is_mem_defined ( base, size, &bad_addr );
if (MC_Ok != res) {
- Bool isUnaddr = ( MC_AddrErr == res ? True : False );
+ Bool isAddrErr = ( MC_AddrErr == res ? True : False );
switch (part) {
case Vg_CoreSysCall:
- mc_record_param_error ( tid, bad_addr, /*isReg*/False,
- isUnaddr, s );
+ mc_record_memparam_error ( tid, bad_addr, isAddrErr, s );
break;
- case Vg_CoreClientReq: // Kludge: make this a CoreMemErr
- mc_record_core_mem_error( tid, isUnaddr, s );
- break;
-
/* If we're being asked to jump to a silly address, record an error
message before potentially crashing the entire system. */
case Vg_CoreTranslate:
tl_assert(part == Vg_CoreSysCall);
res = mc_is_defined_asciiz ( (Addr)str, &bad_addr );
if (MC_Ok != res) {
- Bool isUnaddr = ( MC_AddrErr == res ? True : False );
- mc_record_param_error ( tid, bad_addr, /*isReg*/False, isUnaddr, s );
+ Bool isAddrErr = ( MC_AddrErr == res ? True : False );
+ mc_record_memparam_error ( tid, bad_addr, isAddrErr, s );
}
}
}
if (bad)
- mc_record_param_error ( tid, 0, /*isReg*/True, /*isUnaddr*/False, s );
+ mc_record_regparam_error ( tid, s );
}
/*------------------------------------------------------------*/
-/*--- Error and suppression types ---*/
+/*--- Error types ---*/
/*------------------------------------------------------------*/
+// Different kinds of blocks.
+typedef enum {
+ Block_Mallocd = 111,
+ Block_Freed,
+ Block_Mempool,
+ Block_MempoolChunk,
+ Block_UserG
+} BlockKind;
+
+/* ------------------ Addresses -------------------- */
+
/* The classification of a faulting address. */
typedef
enum {
- Undescribed, // as-yet unclassified
- Stack,
- Unknown, // classification yielded nothing useful
- Freed, Mallocd,
- UserG, // in a user-defined block
- Mempool, // in a mempool
- Register, // in a register; for Param errors only
+ Addr_Undescribed, // as-yet unclassified
+ Addr_Unknown, // classification yielded nothing useful
+ Addr_Stack,
+ Addr_Block,
}
- AddrKind;
+ AddrTag;
-/* Records info about a faulting address. */
typedef
- struct { // Used by:
- AddrKind akind; // ALL
- SizeT blksize; // Freed, Mallocd
- OffT rwoffset; // Freed, Mallocd
- ExeContext* lastchange; // Freed, Mallocd
- ThreadId stack_tid; // Stack
- const Char *desc; // UserG
- Bool maybe_gcc; // True if just below %esp -- could be a gcc bug.
- }
+ struct _AddrInfo
AddrInfo;
-typedef
- enum {
- ParamSupp, // Bad syscall params
- UserSupp, // Errors arising from client-request checks
- CoreMemSupp, // Memory errors in core (pthread ops, signal handling)
+struct _AddrInfo {
+ AddrTag tag;
+ union {
+ // As-yet unclassified.
+ struct { } Undescribed;
- // Use of invalid values of given size (MemCheck only)
- Value0Supp, Value1Supp, Value2Supp, Value4Supp, Value8Supp, Value16Supp,
+ // On a stack.
+ struct {
+ ThreadId tid; // Which thread's stack?
+ } Stack;
- // Invalid read/write attempt at given size
- Addr1Supp, Addr2Supp, Addr4Supp, Addr8Supp, Addr16Supp,
+ // This covers heap blocks (normal and from mempools) and user-defined
+ // blocks.
+ struct {
+ BlockKind block_kind;
+ Char* block_desc; // "block", "mempool" or user-defined
+ SizeT block_szB;
+ OffT rwoffset;
+ ExeContext* lastchange;
+ } Block;
- FreeSupp, // Invalid or mismatching free
- OverlapSupp, // Overlapping blocks in memcpy(), strcpy(), etc
- LeakSupp, // Something to be suppressed in a leak check.
- MempoolSupp, // Memory pool suppression.
- }
- MC_SuppKind;
+ // Classification yielded nothing useful.
+ struct { } Unknown;
+
+ } Addr;
+};
+
+/* ------------------ Errors ----------------------- */
/* What kind of error it is. */
typedef
- enum { ValueErr,
- CoreMemErr, // Error in core op (pthread, signals) or client req
- AddrErr,
- ParamErr, UserErr, /* behaves like an anonymous ParamErr */
- FreeErr, FreeMismatchErr,
- OverlapErr,
- LeakErr,
- IllegalMempoolErr,
- }
- MC_ErrorKind;
-
-/* What kind of memory access is involved in the error? */
-typedef
- enum { ReadAxs, WriteAxs, ExecAxs }
- AxsKind;
+ enum {
+ Err_Value,
+ Err_Cond,
+ Err_CoreMem,
+ Err_Addr,
+ Err_Jump,
+ Err_RegParam,
+ Err_MemParam,
+ Err_User,
+ Err_Free,
+ Err_FreeMismatch,
+ Err_Overlap,
+ Err_Leak,
+ Err_IllegalMempool,
+ }
+ MC_ErrorTag;
+
+
+typedef struct _MC_Error MC_Error;
+
+struct _MC_Error {
+ // Nb: we don't need the tag here, as it's stored in the Error type! Yuk.
+ //MC_ErrorTag tag;
+
+ union {
+ // Use of an undefined value:
+ // - as a pointer in a load or store
+ // - as a jump target
+ struct {
+ SizeT szB; // size of value in bytes
+ } Value;
+
+ // Use of an undefined value in a conditional branch or move.
+ struct {
+ } Cond;
+
+ // Addressability error in core (signal-handling) operation.
+ // It would be good to get rid of this error kind, merge it with
+ // another one somehow.
+ struct {
+ } CoreMem;
+
+ // Use of an unaddressable memory location in a load or store.
+ struct {
+ Bool isWrite; // read or write?
+ SizeT szB; // not used for exec (jump) errors
+ Bool maybe_gcc; // True if just below %esp -- could be a gcc bug
+ AddrInfo ai;
+ } Addr;
+
+ // Jump to an unaddressable memory location.
+ struct {
+ AddrInfo ai;
+ } Jump;
+
+ // System call register input contains undefined bytes.
+ struct {
+ } RegParam;
+
+ // System call memory input contains undefined/unaddressable bytes
+ struct {
+ Bool isAddrErr; // Addressability or definedness error?
+ AddrInfo ai;
+ } MemParam;
+
+ // Problem found from a client request like CHECK_MEM_IS_ADDRESSABLE.
+ struct {
+ Bool isAddrErr; // Addressability or definedness error?
+ AddrInfo ai;
+ } User;
+
+ // Program tried to free() something that's not a heap block (this
+ // covers double-frees). */
+ struct {
+ AddrInfo ai;
+ } Free;
+
+ // Program allocates heap block with one function
+ // (malloc/new/new[]/custom) and deallocates with not the matching one.
+ struct {
+ AddrInfo ai;
+ } FreeMismatch;
+
+ // Call to strcpy, memcpy, etc, with overlapping blocks.
+ struct {
+ Addr src; // Source block
+ Addr dst; // Destination block
+ Int szB; // Size in bytes; 0 if unused.
+ } Overlap;
+
+ // A memory leak.
+ struct {
+ UInt n_this_record;
+ UInt n_total_records;
+ LossRecord* lossRecord;
+ } Leak;
+
+ // A memory pool error.
+ struct {
+ AddrInfo ai;
+ } IllegalMempool;
+
+ } Err;
+};
-/* Extra context for memory errors */
-typedef
- struct { // Used by:
- AxsKind axskind; // AddrErr
- Int size; // AddrErr, ValueErr
- AddrInfo addrinfo; // {Addr,Free,FreeMismatch,Param,User}Err
- Bool isUnaddr; // {CoreMem,Param,User}Err
- }
- MC_Error;
/*------------------------------------------------------------*/
/*--- Printing errors ---*/
/*------------------------------------------------------------*/
-static void mc_pp_AddrInfo ( Addr a, AddrInfo* ai )
+static void mc_pp_AddrInfo ( Addr a, AddrInfo* ai, Bool maybe_gcc )
{
HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
- switch (ai->akind) {
- case Stack:
- VG_(message)(Vg_UserMsg,
- "%sAddress 0x%llx is on thread %d's stack%s",
- xpre, (ULong)a, ai->stack_tid, xpost);
- break;
- case Unknown:
- if (ai->maybe_gcc) {
+ switch (ai->tag) {
+ case Addr_Unknown:
+ if (maybe_gcc) {
VG_(message)(Vg_UserMsg,
"%sAddress 0x%llx is just below the stack ptr. "
"To suppress, use: --workaround-gcc296-bugs=yes%s",
xpre, (ULong)a, xpost);
}
break;
- case Freed: case Mallocd: case UserG: case Mempool: {
+
+ case Addr_Stack:
+ VG_(message)(Vg_UserMsg,
+ "%sAddress 0x%llx is on thread %d's stack%s",
+ xpre, (ULong)a, ai->Addr.Stack.tid, xpost);
+ break;
+
+ case Addr_Block: {
+ SizeT block_szB = ai->Addr.Block.block_szB;
+ OffT rwoffset = ai->Addr.Block.rwoffset;
SizeT delta;
const Char* relative;
- const Char* kind;
- if (ai->akind == Mempool) {
- kind = "mempool";
- } else {
- kind = "block";
- }
- if (ai->desc != NULL)
- kind = ai->desc;
- if (ai->rwoffset < 0) {
- delta = (SizeT)(- ai->rwoffset);
+ if (rwoffset < 0) {
+ delta = (SizeT)(-rwoffset);
relative = "before";
- } else if (ai->rwoffset >= ai->blksize) {
- delta = ai->rwoffset - ai->blksize;
+ } else if (rwoffset >= block_szB) {
+ delta = rwoffset - block_szB;
relative = "after";
} else {
- delta = ai->rwoffset;
+ delta = rwoffset;
relative = "inside";
}
VG_(message)(Vg_UserMsg,
"%sAddress 0x%lx is %,lu bytes %s a %s of size %,lu %s%s",
xpre,
- a, delta, relative, kind,
- ai->blksize,
- ai->akind==Mallocd ? "alloc'd"
- : ai->akind==Freed ? "free'd"
- : "client-defined",
+ a, delta, relative, ai->Addr.Block.block_desc,
+ block_szB,
+ ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
+ : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
+ : "client-defined",
xpost);
- VG_(pp_ExeContext)(ai->lastchange);
+ VG_(pp_ExeContext)(ai->Addr.Block.lastchange);
break;
}
- case Register:
- // print nothing
- tl_assert(0 == a);
- break;
+
default:
VG_(tool_panic)("mc_pp_AddrInfo");
}
}
-static void mc_pp_Error ( Error* err )
+static const HChar* str_leak_lossmode ( Reachedness lossmode )
+{
+ const HChar *loss = "?";
+ switch (lossmode) {
+ case Unreached: loss = "definitely lost"; break;
+ case IndirectLeak: loss = "indirectly lost"; break;
+ case Interior: loss = "possibly lost"; break;
+ case Proper: loss = "still reachable"; break;
+ }
+ return loss;
+}
+
+static const HChar* xml_leak_kind ( Reachedness lossmode )
{
- MC_Error* err_extra = VG_(get_error_extra)(err);
+ const HChar *loss = "?";
+ switch (lossmode) {
+ case Unreached: loss = "Leak_DefinitelyLost"; break;
+ case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
+ case Interior: loss = "Leak_PossiblyLost"; break;
+ case Proper: loss = "Leak_StillReachable"; break;
+ }
+ return loss;
+}
+static void mc_pp_msg( Char* xml_name, Error* err, const HChar* format, ... )
+{
HChar* xpre = VG_(clo_xml) ? " <what>" : "";
HChar* xpost = VG_(clo_xml) ? "</what>" : "";
+ Char buf[256];
+ va_list vargs;
+
+ if (VG_(clo_xml))
+ VG_(message)(Vg_UserMsg, " <kind>%s</kind>", xml_name);
+ // Stick xpre and xpost on the front and back of the format string.
+ VG_(snprintf)(buf, 256, "%s%s%s", xpre, format, xpost);
+ va_start(vargs, format);
+ VG_(vmessage) ( Vg_UserMsg, buf, vargs );
+ va_end(vargs);
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+}
+
+static void mc_pp_Error ( Error* err )
+{
+ MC_Error* extra = VG_(get_error_extra)(err);
switch (VG_(get_error_kind)(err)) {
- case CoreMemErr: {
- Char* s = ( err_extra->isUnaddr ? "unaddressable" : "uninitialised" );
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>CoreMemError</kind>");
- /* What the hell *is* a CoreMemError? jrs 2005-May-18 */
- VG_(message)(Vg_UserMsg, "%s%s contains %s byte(s)%s",
- xpre, VG_(get_error_string)(err), s, xpost);
-
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ case Err_CoreMem: {
+ /* What the hell *is* a CoreMemError? jrs 2005-May-18 */
+ /* As of 2006-Dec-14, it's caused by unaddressable bytes in a
+ signal handler frame. --njn */
+ mc_pp_msg("CoreMemError", err,
+ "%s contains unaddressable byte(s)",
+ VG_(get_error_string)(err));
break;
-
}
- case ValueErr:
- if (err_extra->size == 0) {
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>UninitCondition</kind>");
- VG_(message)(Vg_UserMsg, "%sConditional jump or move depends"
- " on uninitialised value(s)%s",
- xpre, xpost);
- } else {
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>UninitValue</kind>");
- VG_(message)(Vg_UserMsg,
- "%sUse of uninitialised value of size %d%s",
- xpre, err_extra->size, xpost);
- }
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ case Err_Value:
+ mc_pp_msg("UninitValue", err,
+ "Use of uninitialised value of size %d",
+ extra->Err.Value.szB);
break;
- case ParamErr: {
- Bool isReg = ( Register == err_extra->addrinfo.akind );
- Char* s1 = ( isReg ? "contains" : "points to" );
- Char* s2 = ( err_extra->isUnaddr ? "unaddressable" : "uninitialised" );
- if (isReg) tl_assert(!err_extra->isUnaddr);
-
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>SyscallParam</kind>");
- VG_(message)(Vg_UserMsg, "%sSyscall param %s %s %s byte(s)%s",
- xpre, VG_(get_error_string)(err), s1, s2, xpost);
+ case Err_Cond:
+ mc_pp_msg("UninitCondition", err,
+ "Conditional jump or move depends"
+ " on uninitialised value(s)");
+ break;
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+ case Err_RegParam:
+ mc_pp_msg("SyscallParam", err,
+ "Syscall param %s contains uninitialised byte(s)",
+ VG_(get_error_string)(err));
break;
- }
- case UserErr: {
- Char* s = ( err_extra->isUnaddr ? "Unaddressable" : "Uninitialised" );
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>ClientCheck</kind>");
- VG_(message)(Vg_UserMsg,
- "%s%s byte(s) found during client check request%s",
- xpre, s, xpost);
+ case Err_MemParam:
+ mc_pp_msg("SyscallParam", err,
+ "Syscall param %s points to %s byte(s)",
+ VG_(get_error_string)(err),
+ ( extra->Err.MemParam.isAddrErr
+ ? "unaddressable" : "uninitialised" ));
+ mc_pp_AddrInfo(VG_(get_error_address)(err),
+ &extra->Err.MemParam.ai, False);
+ break;
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+ case Err_User:
+ mc_pp_msg("ClientCheck", err,
+ "%s byte(s) found during client check request",
+ ( extra->Err.User.isAddrErr
+ ? "Unaddressable" : "Uninitialised" ));
+ mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.User.ai,
+ False);
break;
- }
- case FreeErr:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>InvalidFree</kind>");
- VG_(message)(Vg_UserMsg,
- "%sInvalid free() / delete / delete[]%s",
- xpre, xpost);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+
+ case Err_Free:
+ mc_pp_msg("InvalidFree", err,
+ "Invalid free() / delete / delete[]");
+ mc_pp_AddrInfo(VG_(get_error_address)(err),
+ &extra->Err.Free.ai, False);
break;
- case FreeMismatchErr:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>MismatchedFree</kind>");
- VG_(message)(Vg_UserMsg,
- "%sMismatched free() / delete / delete []%s",
- xpre, xpost);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+ case Err_FreeMismatch:
+ mc_pp_msg("MismatchedFree", err,
+ "Mismatched free() / delete / delete []");
+ mc_pp_AddrInfo(VG_(get_error_address)(err),
+ &extra->Err.FreeMismatch.ai, False);
break;
- case AddrErr:
- switch (err_extra->axskind) {
- case ReadAxs:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>InvalidRead</kind>");
- VG_(message)(Vg_UserMsg,
- "%sInvalid read of size %d%s",
- xpre, err_extra->size, xpost );
- break;
- case WriteAxs:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>InvalidWrite</kind>");
- VG_(message)(Vg_UserMsg,
- "%sInvalid write of size %d%s",
- xpre, err_extra->size, xpost );
- break;
- case ExecAxs:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>InvalidJump</kind>");
- VG_(message)(Vg_UserMsg,
- "%sJump to the invalid address "
- "stated on the next line%s",
- xpre, xpost);
- break;
- default:
- VG_(tool_panic)("mc_pp_Error(axskind)");
+ case Err_Addr:
+ if (extra->Err.Addr.isWrite) {
+ mc_pp_msg("InvalidWrite", err,
+ "Invalid write of size %d",
+ extra->Err.Addr.szB);
+ } else {
+ mc_pp_msg("InvalidRead", err,
+ "Invalid read of size %d",
+ extra->Err.Addr.szB);
}
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+ mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.Addr.ai,
+ extra->Err.Addr.maybe_gcc);
break;
- case OverlapErr: {
- OverlapExtra* ov_extra = (OverlapExtra*)VG_(get_error_extra)(err);
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>Overlap</kind>");
- if (ov_extra->len == -1)
- VG_(message)(Vg_UserMsg,
- "%sSource and destination overlap in %s(%p, %p)%s",
- xpre,
- VG_(get_error_string)(err),
- ov_extra->dst, ov_extra->src,
- xpost);
+ case Err_Jump:
+ mc_pp_msg("InvalidJump", err,
+ "Jump to the invalid address stated on the next line");
+ mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.Jump.ai,
+ False);
+ break;
+
+ case Err_Overlap:
+ if (extra->Err.Overlap.szB == 0)
+ mc_pp_msg("Overlap", err,
+ "Source and destination overlap in %s(%p, %p)",
+ VG_(get_error_string)(err),
+ extra->Err.Overlap.dst, extra->Err.Overlap.src);
else
- VG_(message)(Vg_UserMsg,
- "%sSource and destination overlap in %s(%p, %p, %d)%s",
- xpre,
- VG_(get_error_string)(err),
- ov_extra->dst, ov_extra->src, ov_extra->len,
- xpost);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ mc_pp_msg("Overlap", err,
+ "Source and destination overlap in %s(%p, %p, %d)",
+ VG_(get_error_string)(err),
+ extra->Err.Overlap.dst, extra->Err.Overlap.src,
+ extra->Err.Overlap.szB);
break;
- }
- case LeakErr: {
- MC_(pp_LeakError)(err_extra);
+
+ case Err_IllegalMempool:
+ mc_pp_msg("InvalidMemPool", err,
+ "Illegal memory pool address");
+ mc_pp_AddrInfo(VG_(get_error_address)(err),
+ &extra->Err.IllegalMempool.ai, False);
break;
- }
- case IllegalMempoolErr:
- if (VG_(clo_xml))
- VG_(message)(Vg_UserMsg, " <kind>InvalidMemPool</kind>");
- VG_(message)(Vg_UserMsg, "%sIllegal memory pool address%s",
- xpre, xpost);
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- mc_pp_AddrInfo(VG_(get_error_address)(err), &err_extra->addrinfo);
+ case Err_Leak: {
+ HChar* xpre = VG_(clo_xml) ? " <what>" : "";
+ HChar* xpost = VG_(clo_xml) ? "</what>" : "";
+ UInt n_this_record = extra->Err.Leak.n_this_record;
+ UInt n_total_records = extra->Err.Leak.n_total_records;
+ LossRecord* l = extra->Err.Leak.lossRecord;
+
+ if (VG_(clo_xml)) {
+ VG_(message)(Vg_UserMsg, " <kind>%t</kind>",
+ xml_leak_kind(l->loss_mode));
+ } else {
+ VG_(message)(Vg_UserMsg, "");
+ }
+
+ if (l->indirect_bytes) {
+ VG_(message)(Vg_UserMsg,
+ "%s%,lu (%,lu direct, %,lu indirect) bytes in %,u blocks"
+ " are %s in loss record %,u of %,u%s",
+ xpre,
+ l->total_bytes + l->indirect_bytes,
+ l->total_bytes, l->indirect_bytes, l->num_blocks,
+ str_leak_lossmode(l->loss_mode), n_this_record, n_total_records,
+ xpost
+ );
+ if (VG_(clo_xml)) {
+ // Nb: don't put commas in these XML numbers
+ VG_(message)(Vg_UserMsg, " <leakedbytes>%lu</leakedbytes>",
+ l->total_bytes + l->indirect_bytes);
+ VG_(message)(Vg_UserMsg, " <leakedblocks>%u</leakedblocks>",
+ l->num_blocks);
+ }
+ } else {
+ VG_(message)(
+ Vg_UserMsg,
+ "%s%,lu bytes in %,u blocks are %s in loss record %,u of %,u%s",
+ xpre,
+ l->total_bytes, l->num_blocks,
+ str_leak_lossmode(l->loss_mode), n_this_record, n_total_records,
+ xpost
+ );
+ if (VG_(clo_xml)) {
+ VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
+ l->total_bytes);
+ VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
+ l->num_blocks);
+ }
+ }
+ VG_(pp_ExeContext)(l->allocated_at);
break;
+ }
default:
VG_(printf)("Error:\n unknown Memcheck error code %d\n",
return False;
}
-static void mc_clear_MC_Error ( MC_Error* err_extra )
-{
- err_extra->axskind = ReadAxs;
- err_extra->size = 0;
- err_extra->isUnaddr = True;
- err_extra->addrinfo.akind = Unknown;
- err_extra->addrinfo.blksize = 0;
- err_extra->addrinfo.rwoffset = 0;
- err_extra->addrinfo.lastchange = NULL;
- err_extra->addrinfo.stack_tid = VG_INVALID_THREADID;
- err_extra->addrinfo.maybe_gcc = False;
- err_extra->addrinfo.desc = NULL;
-}
+/* --- Called from generated and non-generated code --- */
-/* This one called from generated code and non-generated code. */
-static void mc_record_address_error ( ThreadId tid, Addr a, Int size,
+static void mc_record_address_error ( ThreadId tid, Addr a, Int szB,
Bool isWrite )
{
- MC_Error err_extra;
+ MC_Error extra;
Bool just_below_esp;
if (in_ignored_range(a))
best we can do is to 'act normal' and mark the A bits in the
normal way as noaccess, but then hide any reads from that page
that get reported here. */
- if ((!isWrite) && a >= 0 && a < 4096 && a+size <= 4096)
+ if ((!isWrite) && a >= 0 && a < 4096 && a+szB <= 4096)
return;
/* Appalling AIX hack. It suppresses reads done by glink
fragments. Getting rid of this would require figuring out
somehow where the referenced data areas are (and their
sizes). */
- if ((!isWrite) && size == sizeof(Word)) {
+ if ((!isWrite) && szB == sizeof(Word)) {
UInt i1, i2;
UInt* pc = (UInt*)VG_(get_IP)(tid);
if (sizeof(Word) == 4) {
if (MC_(clo_workaround_gcc296_bugs) && just_below_esp)
return;
- mc_clear_MC_Error( &err_extra );
- err_extra.axskind = isWrite ? WriteAxs : ReadAxs;
- err_extra.size = size;
- err_extra.addrinfo.akind = Undescribed;
- err_extra.addrinfo.maybe_gcc = just_below_esp;
- VG_(maybe_record_error)( tid, AddrErr, a, /*s*/NULL, &err_extra );
+ extra.Err.Addr.isWrite = isWrite;
+ extra.Err.Addr.szB = szB;
+ extra.Err.Addr.maybe_gcc = just_below_esp;
+ extra.Err.Addr.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_Addr, a, /*s*/NULL, &extra );
}
-/* These ones are called from non-generated code */
+static void mc_record_value_error ( ThreadId tid, Int szB )
+{
+ MC_Error extra;
+ tl_assert(MC_(clo_undef_value_errors));
+ extra.Err.Value.szB = szB;
+ VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra );
+}
+
+static void mc_record_cond_error ( ThreadId tid )
+{
+ tl_assert(MC_(clo_undef_value_errors));
+ VG_(maybe_record_error)( tid, Err_Cond, /*addr*/0, /*s*/NULL, /*extra*/NULL);
+}
+
+/* --- Called from non-generated code --- */
/* This is for memory errors in pthread functions, as opposed to pthread API
errors which are found by the core. */
-static void mc_record_core_mem_error ( ThreadId tid, Bool isUnaddr, Char* msg )
+static void mc_record_core_mem_error ( ThreadId tid, Bool isAddrErr, Char* msg )
{
- MC_Error err_extra;
-
- mc_clear_MC_Error( &err_extra );
- err_extra.isUnaddr = isUnaddr;
- VG_(maybe_record_error)( tid, CoreMemErr, /*addr*/0, msg, &err_extra );
+ VG_(maybe_record_error)( tid, Err_CoreMem, /*addr*/0, msg, /*extra*/NULL );
}
-// Three kinds of param errors:
-// - register arg contains undefined bytes
-// - memory arg is unaddressable
-// - memory arg contains undefined bytes
-// 'isReg' and 'isUnaddr' dictate which of these it is.
-static void mc_record_param_error ( ThreadId tid, Addr a, Bool isReg,
- Bool isUnaddr, Char* msg )
+static void mc_record_regparam_error ( ThreadId tid, Char* msg )
{
- MC_Error err_extra;
+ tl_assert(VG_INVALID_THREADID != tid);
+ VG_(maybe_record_error)( tid, Err_RegParam, /*addr*/0, msg, /*extra*/NULL );
+}
- if (!isUnaddr) tl_assert(MC_(clo_undef_value_errors));
+static void mc_record_memparam_error ( ThreadId tid, Addr a,
+ Bool isAddrErr, Char* msg )
+{
+ MC_Error extra;
tl_assert(VG_INVALID_THREADID != tid);
- if (isUnaddr) tl_assert(!isReg); // unaddressable register is impossible
- mc_clear_MC_Error( &err_extra );
- err_extra.addrinfo.akind = ( isReg ? Register : Undescribed );
- err_extra.isUnaddr = isUnaddr;
- VG_(maybe_record_error)( tid, ParamErr, a, msg, &err_extra );
+ if (!isAddrErr)
+ tl_assert(MC_(clo_undef_value_errors));
+ extra.Err.MemParam.isAddrErr = isAddrErr;
+ extra.Err.MemParam.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_MemParam, a, msg, &extra );
}
static void mc_record_jump_error ( ThreadId tid, Addr a )
{
- MC_Error err_extra;
-
+ MC_Error extra;
tl_assert(VG_INVALID_THREADID != tid);
- mc_clear_MC_Error( &err_extra );
- err_extra.axskind = ExecAxs;
- err_extra.size = 1; // size only used for suppressions
- err_extra.addrinfo.akind = Undescribed;
- VG_(maybe_record_error)( tid, AddrErr, a, /*s*/NULL, &err_extra );
+ extra.Err.Jump.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_Jump, a, /*s*/NULL, &extra );
}
void MC_(record_free_error) ( ThreadId tid, Addr a )
{
- MC_Error err_extra;
-
+ MC_Error extra;
tl_assert(VG_INVALID_THREADID != tid);
- mc_clear_MC_Error( &err_extra );
- err_extra.addrinfo.akind = Undescribed;
- VG_(maybe_record_error)( tid, FreeErr, a, /*s*/NULL, &err_extra );
+ extra.Err.Free.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_Free, a, /*s*/NULL, &extra );
}
-void MC_(record_illegal_mempool_error) ( ThreadId tid, Addr a )
+void MC_(record_freemismatch_error) ( ThreadId tid, MC_Chunk* mc )
{
- MC_Error err_extra;
-
+ MC_Error extra;
+ AddrInfo* ai = &extra.Err.FreeMismatch.ai;
tl_assert(VG_INVALID_THREADID != tid);
- mc_clear_MC_Error( &err_extra );
- err_extra.addrinfo.akind = Undescribed;
- VG_(maybe_record_error)( tid, IllegalMempoolErr, a, /*s*/NULL, &err_extra );
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_Mallocd; // Nb: Not 'Block_Freed'
+ ai->Addr.Block.block_desc = "block";
+ ai->Addr.Block.block_szB = mc->szB;
+ ai->Addr.Block.rwoffset = 0;
+ ai->Addr.Block.lastchange = mc->where;
+ VG_(maybe_record_error)( tid, Err_FreeMismatch, mc->data, /*s*/NULL,
+ &extra );
}
-void MC_(record_freemismatch_error) ( ThreadId tid, Addr a, MC_Chunk* mc )
+void MC_(record_illegal_mempool_error) ( ThreadId tid, Addr a )
{
- MC_Error err_extra;
- AddrInfo* ai;
-
+ MC_Error extra;
tl_assert(VG_INVALID_THREADID != tid);
- mc_clear_MC_Error( &err_extra );
- ai = &err_extra.addrinfo;
- ai->akind = Mallocd; // Nb: not 'Freed'
- ai->blksize = mc->size;
- ai->rwoffset = (Int)a - (Int)mc->data;
- ai->lastchange = mc->where;
- VG_(maybe_record_error)( tid, FreeMismatchErr, a, /*s*/NULL, &err_extra );
+ extra.Err.IllegalMempool.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_IllegalMempool, a, /*s*/NULL, &extra );
}
-static void mc_record_overlap_error ( ThreadId tid,
- Char* function, OverlapExtra* ov_extra )
+static void mc_record_overlap_error ( ThreadId tid, Char* function,
+ Addr src, Addr dst, SizeT szB )
{
+ MC_Error extra;
+ tl_assert(VG_INVALID_THREADID != tid);
+ extra.Err.Overlap.src = src;
+ extra.Err.Overlap.dst = dst;
+ extra.Err.Overlap.szB = szB;
VG_(maybe_record_error)(
- tid, OverlapErr, /*addr*/0, /*s*/function, ov_extra );
+ tid, Err_Overlap, /*addr*/0, /*s*/function, &extra );
}
-Bool MC_(record_leak_error) ( ThreadId tid, /*LeakExtra*/void* leak_extra,
- ExeContext* where, Bool print_record )
+Bool MC_(record_leak_error) ( ThreadId tid, UInt n_this_record,
+ UInt n_total_records, LossRecord* lossRecord,
+ Bool print_record )
{
+ MC_Error extra;
+ extra.Err.Leak.n_this_record = n_this_record;
+ extra.Err.Leak.n_total_records = n_total_records;
+ extra.Err.Leak.lossRecord = lossRecord;
return
- VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
- /*extra*/leak_extra, where, print_record,
+ VG_(unique_error) ( tid, Err_Leak, /*Addr*/0, /*s*/NULL, &extra,
+ lossRecord->allocated_at, print_record,
/*allow_GDB_attach*/False, /*count_error*/False );
}
-
-/* Creates a copy of the 'extra' part, updates the copy with address info if
- necessary, and returns the copy. */
-/* This one called from generated code and non-generated code. */
-static void mc_record_value_error ( ThreadId tid, Int size )
+static void mc_record_user_error ( ThreadId tid, Addr a, Bool isAddrErr )
{
- MC_Error err_extra;
-
- tl_assert(MC_(clo_undef_value_errors));
- mc_clear_MC_Error( &err_extra );
- err_extra.size = size;
- err_extra.isUnaddr = False;
- VG_(maybe_record_error)( tid, ValueErr, /*addr*/0, /*s*/NULL, &err_extra );
-}
-
-/* This called from non-generated code */
-
-static void mc_record_user_error ( ThreadId tid, Addr a, Bool isWrite,
- Bool isUnaddr )
-{
- MC_Error err_extra;
+ MC_Error extra;
tl_assert(VG_INVALID_THREADID != tid);
- mc_clear_MC_Error( &err_extra );
- err_extra.addrinfo.akind = Undescribed;
- err_extra.isUnaddr = isUnaddr;
- VG_(maybe_record_error)( tid, UserErr, a, /*s*/NULL, &err_extra );
+ extra.Err.User.isAddrErr = isAddrErr;
+ extra.Err.User.ai.tag = Addr_Undescribed;
+ VG_(maybe_record_error)( tid, Err_User, a, /*s*/NULL, &extra );
}
-__attribute__ ((unused))
-static Bool eq_AddrInfo ( VgRes res, AddrInfo* ai1, AddrInfo* ai2 )
-{
- if (ai1->akind != Undescribed
- && ai2->akind != Undescribed
- && ai1->akind != ai2->akind)
- return False;
- if (ai1->akind == Freed || ai1->akind == Mallocd) {
- if (ai1->blksize != ai2->blksize)
- return False;
- if (!VG_(eq_ExeContext)(res, ai1->lastchange, ai2->lastchange))
- return False;
- }
- return True;
-}
+/*------------------------------------------------------------*/
+/*--- Other error operations ---*/
+/*------------------------------------------------------------*/
/* Compare error contexts, to detect duplicates. Note that if they
are otherwise the same, the faulting addrs and associated rwoffsets
are allowed to be different. */
static Bool mc_eq_Error ( VgRes res, Error* e1, Error* e2 )
{
- MC_Error* e1_extra = VG_(get_error_extra)(e1);
- MC_Error* e2_extra = VG_(get_error_extra)(e2);
+ MC_Error* extra1 = VG_(get_error_extra)(e1);
+ MC_Error* extra2 = VG_(get_error_extra)(e2);
/* Guaranteed by calling function */
tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
switch (VG_(get_error_kind)(e1)) {
- case CoreMemErr: {
+ case Err_CoreMem: {
Char *e1s, *e2s;
- if (e1_extra->isUnaddr != e2_extra->isUnaddr) return False;
e1s = VG_(get_error_string)(e1);
e2s = VG_(get_error_string)(e2);
- if (e1s == e2s) return True;
- if (0 == VG_(strcmp)(e1s, e2s)) return True;
+ if (e1s == e2s) return True;
+ if (VG_STREQ(e1s, e2s)) return True;
return False;
}
+ case Err_RegParam:
+ return VG_STREQ(VG_(get_error_string)(e1), VG_(get_error_string)(e2));
+
// Perhaps we should also check the addrinfo.akinds for equality.
// That would result in more error reports, but only in cases where
// a register contains uninitialised bytes and points to memory
// containing uninitialised bytes. Currently, the 2nd of those to be
// detected won't be reported. That is (nearly?) always the memory
// error, which is good.
- case ParamErr:
- if (0 != VG_(strcmp)(VG_(get_error_string)(e1),
- VG_(get_error_string)(e2))) return False;
+ case Err_MemParam:
+ if (!VG_STREQ(VG_(get_error_string)(e1),
+ VG_(get_error_string)(e2))) return False;
// fall through
- case UserErr:
- if (e1_extra->isUnaddr != e2_extra->isUnaddr) return False;
+ case Err_User:
+ return ( extra1->Err.User.isAddrErr == extra2->Err.User.isAddrErr
+ ? True : False );
+
+ case Err_Free:
+ case Err_FreeMismatch:
+ case Err_Jump:
+ case Err_IllegalMempool:
+ case Err_Overlap:
+ case Err_Cond:
return True;
- case FreeErr:
- case FreeMismatchErr:
- /* JRS 2002-Aug-26: comparing addrs seems overkill and can
- cause excessive duplication of errors. Not even AddrErr
- below does that. So don't compare either the .addr field
- or the .addrinfo fields. */
- /* if (e1->addr != e2->addr) return False; */
- /* if (!eq_AddrInfo(res, &e1_extra->addrinfo, &e2_extra->addrinfo))
- return False;
- */
- return True;
-
- case AddrErr:
- /* if (e1_extra->axskind != e2_extra->axskind) return False; */
- if (e1_extra->size != e2_extra->size) return False;
- /*
- if (!eq_AddrInfo(res, &e1_extra->addrinfo, &e2_extra->addrinfo))
- return False;
- */
- return True;
-
- case ValueErr:
- if (e1_extra->size != e2_extra->size) return False;
- return True;
+ case Err_Addr:
+ return ( extra1->Err.Addr.szB == extra2->Err.Addr.szB
+ ? True : False );
- case OverlapErr:
- return True;
+ case Err_Value:
+ return ( extra1->Err.Value.szB == extra2->Err.Value.szB
+ ? True : False );
- case LeakErr:
- VG_(tool_panic)("Shouldn't get LeakErr in mc_eq_Error,\n"
+ case Err_Leak:
+ VG_(tool_panic)("Shouldn't get Err_Leak in mc_eq_Error,\n"
"since it's handled with VG_(unique_error)()!");
- case IllegalMempoolErr:
- return True;
-
default:
VG_(printf)("Error:\n unknown error code %d\n",
VG_(get_error_kind)(e1));
// in some cases this could result in an incorrect description (eg.
// saying "12 bytes after block A" when really it's within block B.
// Fixing would require adding redzone size to MC_Chunks, though.
- return VG_(addr_is_in_block)( a, mc->data, mc->size,
+ return VG_(addr_is_in_block)( a, mc->data, mc->szB,
MC_MALLOC_REDZONE_SZB );
}
// Forward declaration
static Bool client_perm_maybe_describe( Addr a, AddrInfo* ai );
+
/* Describe an address as best you can, for error messages,
putting the result in ai. */
static void describe_addr ( Addr a, AddrInfo* ai )
{
MC_Chunk* mc;
- ThreadId tid;
- Addr stack_min, stack_max;
+ ThreadId tid;
+ Addr stack_min, stack_max;
+
+ tl_assert(Addr_Undescribed == ai->tag);
/* Perhaps it's a user-def'd block? */
if (client_perm_maybe_describe( a, ai ))
VG_(thread_stack_reset_iter)();
while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
if (stack_min <= a && a <= stack_max) {
- ai->akind = Stack;
- ai->stack_tid = tid;
+ ai->tag = Addr_Stack;
+ ai->Addr.Stack.tid = tid;
return;
}
}
mc = MC_(get_freed_list_head)();
while (mc) {
if (addr_is_in_MC_Chunk(mc, a)) {
- ai->akind = Freed;
- ai->blksize = mc->size;
- ai->rwoffset = (Int)a - (Int)mc->data;
- ai->lastchange = mc->where;
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_Freed;
+ ai->Addr.Block.block_desc = "block";
+ ai->Addr.Block.block_szB = mc->szB;
+ ai->Addr.Block.rwoffset = (Int)a - (Int)mc->data;
+ ai->Addr.Block.lastchange = mc->where;
return;
}
mc = mc->next;
VG_(HT_ResetIter)(MC_(malloc_list));
while ( (mc = VG_(HT_Next)(MC_(malloc_list))) ) {
if (addr_is_in_MC_Chunk(mc, a)) {
- ai->akind = Mallocd;
- ai->blksize = mc->size;
- ai->rwoffset = (Int)(a) - (Int)mc->data;
- ai->lastchange = mc->where;
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_Mallocd;
+ ai->Addr.Block.block_desc = "block";
+ ai->Addr.Block.block_szB = mc->szB;
+ ai->Addr.Block.rwoffset = (Int)a - (Int)mc->data;
+ ai->Addr.Block.lastchange = mc->where;
return;
}
}
/* Clueless ... */
- ai->akind = Unknown;
+ ai->tag = Addr_Unknown;
return;
}
/* Updates the copy with address info if necessary (but not for all errors). */
static UInt mc_update_extra( Error* err )
{
+ MC_Error* extra = VG_(get_error_extra)(err);
+
switch (VG_(get_error_kind)(err)) {
- // These two don't have addresses associated with them, and so don't
+ // These ones don't have addresses associated with them, and so don't
// need any updating.
- case CoreMemErr:
- case ValueErr: {
- MC_Error* extra = VG_(get_error_extra)(err);
- tl_assert(Unknown == extra->addrinfo.akind);
+ case Err_CoreMem:
+ case Err_Value:
+ case Err_Cond:
+ case Err_Overlap:
+ case Err_RegParam:
+ // For Err_Leaks the returned size does not matter -- they are always
+ // shown with VG_(unique_error)() so they 'extra' not copied. But we make it
+ // consistent with the others.
+ case Err_Leak:
return sizeof(MC_Error);
- }
- // ParamErrs sometimes involve a memory address; call describe_addr() in
- // this case.
- case ParamErr: {
- MC_Error* extra = VG_(get_error_extra)(err);
- tl_assert(Undescribed == extra->addrinfo.akind ||
- Register == extra->addrinfo.akind);
- if (Undescribed == extra->addrinfo.akind)
- describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
+ // These ones always involve a memory address.
+ case Err_Addr:
+ describe_addr ( VG_(get_error_address)(err), &extra->Err.Addr.ai );
return sizeof(MC_Error);
- }
-
- // These four always involve a memory address.
- case AddrErr:
- case UserErr:
- case FreeErr:
- case IllegalMempoolErr: {
- MC_Error* extra = VG_(get_error_extra)(err);
- tl_assert(Undescribed == extra->addrinfo.akind);
- describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
+ case Err_MemParam:
+ describe_addr ( VG_(get_error_address)(err), &extra->Err.MemParam.ai );
+ return sizeof(MC_Error);
+ case Err_Jump:
+ describe_addr ( VG_(get_error_address)(err), &extra->Err.Jump.ai );
+ return sizeof(MC_Error);
+ case Err_User:
+ describe_addr ( VG_(get_error_address)(err), &extra->Err.User.ai );
+ return sizeof(MC_Error);
+ case Err_Free:
+ describe_addr ( VG_(get_error_address)(err), &extra->Err.Free.ai );
+ return sizeof(MC_Error);
+ case Err_IllegalMempool:
+ describe_addr ( VG_(get_error_address)(err),
+ &extra->Err.IllegalMempool.ai );
return sizeof(MC_Error);
- }
- // FreeMismatchErrs have already had their address described; this is
+ // Err_FreeMismatches have already had their address described; this is
// possible because we have the MC_Chunk on hand when the error is
// detected. However, the address may be part of a user block, and if so
// we override the pre-determined description with a user block one.
- case FreeMismatchErr: {
- MC_Error* extra = VG_(get_error_extra)(err);
- tl_assert(extra && Mallocd == extra->addrinfo.akind);
+ case Err_FreeMismatch: {
+ tl_assert(extra && Block_Mallocd ==
+ extra->Err.FreeMismatch.ai.Addr.Block.block_kind);
(void)client_perm_maybe_describe( VG_(get_error_address)(err),
- &(extra->addrinfo) );
+ &extra->Err.FreeMismatch.ai );
return sizeof(MC_Error);
}
- // No memory address involved with these ones. Nb: for LeakErrs the
- // returned size does not matter -- LeakErrs are always shown with
- // VG_(unique_error)() so they're not copied.
- case LeakErr: return 0;
- case OverlapErr: return sizeof(OverlapExtra);
-
default: VG_(tool_panic)("mc_update_extra: bad errkind");
}
}
/*--- Suppressions ---*/
/*------------------------------------------------------------*/
+typedef
+ enum {
+ ParamSupp, // Bad syscall params
+ UserSupp, // Errors arising from client-request checks
+ CoreMemSupp, // Memory errors in core (pthread ops, signal handling)
+
+ // Undefined value errors of given size
+ Value1Supp, Value2Supp, Value4Supp, Value8Supp, Value16Supp,
+
+ // Undefined value error in conditional.
+ CondSupp,
+
+ // Unaddressable read/write attempt at given size
+ Addr1Supp, Addr2Supp, Addr4Supp, Addr8Supp, Addr16Supp,
+
+ JumpSupp, // Jump to unaddressable target
+ FreeSupp, // Invalid or mismatching free
+ OverlapSupp, // Overlapping blocks in memcpy(), strcpy(), etc
+ LeakSupp, // Something to be suppressed in a leak check.
+ MempoolSupp, // Memory pool suppression.
+ }
+ MC_SuppKind;
+
static Bool mc_recognised_suppression ( Char* name, Supp* su )
{
SuppKind skind;
else if (VG_STREQ(name, "Addr4")) skind = Addr4Supp;
else if (VG_STREQ(name, "Addr8")) skind = Addr8Supp;
else if (VG_STREQ(name, "Addr16")) skind = Addr16Supp;
+ else if (VG_STREQ(name, "Jump")) skind = JumpSupp;
else if (VG_STREQ(name, "Free")) skind = FreeSupp;
else if (VG_STREQ(name, "Leak")) skind = LeakSupp;
else if (VG_STREQ(name, "Overlap")) skind = OverlapSupp;
else if (VG_STREQ(name, "Mempool")) skind = MempoolSupp;
- else if (VG_STREQ(name, "Cond")) skind = Value0Supp;
- else if (VG_STREQ(name, "Value0")) skind = Value0Supp;/* backwards compat */
+ else if (VG_STREQ(name, "Cond")) skind = CondSupp;
+ else if (VG_STREQ(name, "Value0")) skind = CondSupp; /* backwards compat */
else if (VG_STREQ(name, "Value1")) skind = Value1Supp;
else if (VG_STREQ(name, "Value2")) skind = Value2Supp;
else if (VG_STREQ(name, "Value4")) skind = Value4Supp;
static Bool mc_error_matches_suppression(Error* err, Supp* su)
{
- Int su_size;
- MC_Error* err_extra = VG_(get_error_extra)(err);
- ErrorKind ekind = VG_(get_error_kind )(err);
+ Int su_szB;
+ MC_Error* extra = VG_(get_error_extra)(err);
+ ErrorKind ekind = VG_(get_error_kind )(err);
switch (VG_(get_supp_kind)(su)) {
case ParamSupp:
- return (ekind == ParamErr
+ return ((ekind == Err_RegParam || ekind == Err_MemParam)
&& VG_STREQ(VG_(get_error_string)(err),
VG_(get_supp_string)(su)));
case UserSupp:
- return (ekind == UserErr);
+ return (ekind == Err_User);
case CoreMemSupp:
- return (ekind == CoreMemErr
+ return (ekind == Err_CoreMem
&& VG_STREQ(VG_(get_error_string)(err),
VG_(get_supp_string)(su)));
- case Value0Supp: su_size = 0; goto value_case;
- case Value1Supp: su_size = 1; goto value_case;
- case Value2Supp: su_size = 2; goto value_case;
- case Value4Supp: su_size = 4; goto value_case;
- case Value8Supp: su_size = 8; goto value_case;
- case Value16Supp:su_size =16; goto value_case;
+ case Value1Supp: su_szB = 1; goto value_case;
+ case Value2Supp: su_szB = 2; goto value_case;
+ case Value4Supp: su_szB = 4; goto value_case;
+ case Value8Supp: su_szB = 8; goto value_case;
+ case Value16Supp:su_szB =16; goto value_case;
value_case:
- return (ekind == ValueErr && err_extra->size == su_size);
+ return (ekind == Err_Value && extra->Err.Value.szB == su_szB);
- case Addr1Supp: su_size = 1; goto addr_case;
- case Addr2Supp: su_size = 2; goto addr_case;
- case Addr4Supp: su_size = 4; goto addr_case;
- case Addr8Supp: su_size = 8; goto addr_case;
- case Addr16Supp:su_size =16; goto addr_case;
+ case CondSupp:
+ return (ekind == Err_Cond);
+
+ case Addr1Supp: su_szB = 1; goto addr_case;
+ case Addr2Supp: su_szB = 2; goto addr_case;
+ case Addr4Supp: su_szB = 4; goto addr_case;
+ case Addr8Supp: su_szB = 8; goto addr_case;
+ case Addr16Supp:su_szB =16; goto addr_case;
addr_case:
- return (ekind == AddrErr && err_extra->size == su_size);
+ return (ekind == Err_Addr && extra->Err.Addr.szB == su_szB);
+
+ case JumpSupp:
+ return (ekind == Err_Jump);
case FreeSupp:
- return (ekind == FreeErr || ekind == FreeMismatchErr);
+ return (ekind == Err_Free || ekind == Err_FreeMismatch);
case OverlapSupp:
- return (ekind == OverlapErr);
+ return (ekind == Err_Overlap);
case LeakSupp:
- return (ekind == LeakErr);
+ return (ekind == Err_Leak);
case MempoolSupp:
- return (ekind == IllegalMempoolErr);
+ return (ekind == Err_IllegalMempool);
default:
VG_(printf)("Error:\n"
{
Char* s;
switch (VG_(get_error_kind)(err)) {
- case ParamErr: return "Param";
- case UserErr: return "User";
- case FreeMismatchErr: return "Free";
- case IllegalMempoolErr: return "Mempool";
- case FreeErr: return "Free";
- case AddrErr:
- switch ( ((MC_Error*)VG_(get_error_extra)(err))->size ) {
+ case Err_RegParam: return "Param";
+ case Err_MemParam: return "Param";
+ case Err_User: return "User";
+ case Err_FreeMismatch: return "Free";
+ case Err_IllegalMempool: return "Mempool";
+ case Err_Free: return "Free";
+ case Err_Jump: return "Jump";
+ case Err_CoreMem: return "CoreMem";
+ case Err_Overlap: return "Overlap";
+ case Err_Leak: return "Leak";
+ case Err_Cond: return "Cond";
+ case Err_Addr: {
+ MC_Error* extra = VG_(get_error_extra)(err);
+ switch ( extra->Err.Addr.szB ) {
case 1: return "Addr1";
case 2: return "Addr2";
case 4: return "Addr4";
case 16: return "Addr16";
default: VG_(tool_panic)("unexpected size for Addr");
}
-
- case ValueErr:
- switch ( ((MC_Error*)VG_(get_error_extra)(err))->size ) {
- case 0: return "Cond";
+ }
+ case Err_Value: {
+ MC_Error* extra = VG_(get_error_extra)(err);
+ switch ( extra->Err.Value.szB ) {
case 1: return "Value1";
case 2: return "Value2";
case 4: return "Value4";
case 16: return "Value16";
default: VG_(tool_panic)("unexpected size for Value");
}
- case CoreMemErr: return "CoreMem";
- case OverlapErr: return "Overlap";
- case LeakErr: return "Leak";
+ }
default: VG_(tool_panic)("get_error_name: unexpected type");
}
VG_(printf)(s);
static void mc_print_extra_suppression_info ( Error* err )
{
- if (ParamErr == VG_(get_error_kind)(err)) {
+ ErrorKind ekind = VG_(get_error_kind )(err);
+ if (Err_RegParam == ekind || Err_MemParam == ekind) {
VG_(printf)(" %s\n", VG_(get_error_string)(err));
}
}
// Handle common case quickly: a is suitably aligned, is mapped, and is
// addressible.
// Convert V bits from compact memory form to expanded register form
- // XXX: set the high 16/48 bits of retval to 1 for 64-bit paranoia?
if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
else {
// Convert V bits from compact memory form to expanded register form
// Handle common case quickly: a is mapped, and the entire
// word32 it lives in is addressible.
- // XXX: set the high 24/56 bits of retval to 1 for 64-bit paranoia?
if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
else {
void MC_(helperc_value_check0_fail) ( void )
{
- mc_record_value_error ( VG_(get_running_tid)(), 0 );
+ mc_record_cond_error ( VG_(get_running_tid)() );
}
void MC_(helperc_value_check1_fail) ( void )
/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
error [no longer used], 3 == addressing error. */
+/* Nb: We used to issue various definedness/addressability errors from here,
+ but we took them out because they ranged from not-very-helpful to
+ downright annoying, and they complicated the error data structures. */
static Int mc_get_or_set_vbits_for_client (
ThreadId tid,
Addr a,
/* Check that arrays are addressible before doing any getting/setting. */
for (i = 0; i < szB; i++) {
- if (VA_BITS2_NOACCESS == get_vabits2(a + i)) {
- mc_record_address_error( tid, a + i, 1, setting ? True : False );
- return 3;
- }
- if (VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
- mc_record_address_error( tid, vbits + i, 1, setting ? False : True );
+ if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
+ VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
return 3;
}
}
/* Do the copy */
if (setting) {
-
- // It's actually a tool ClientReq, but Vg_CoreClientReq is the closest
- // thing we have.
- check_mem_is_defined(Vg_CoreClientReq, tid, "SET_VBITS(vbits)",
- vbits, szB);
-
/* setting */
for (i = 0; i < szB; i++) {
ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
for (i = 0; i < szB; i++) {
ok = get_vbits8(a + i, &vbits8);
tl_assert(ok);
-// XXX: used to do this, but it's a pain
-// if (V_BITS8_DEFINED != vbits8)
-// mc_record_value_error(tid, 1);
((UChar*)vbits)[i] = vbits8;
}
// The bytes in vbits[] have now been set, so mark them as such.
static Bool client_perm_maybe_describe( Addr a, AddrInfo* ai )
{
UInt i;
- /* VG_(printf)("try to identify %d\n", a); */
/* Perhaps it's a general block ? */
for (i = 0; i < cgb_used; i++) {
VG_(HT_ResetIter)(mp->chunks);
while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
if (addr_is_in_MC_Chunk(mc, a)) {
- ai->akind = UserG;
- ai->blksize = mc->size;
- ai->rwoffset = (Int)(a) - (Int)mc->data;
- ai->lastchange = mc->where;
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_MempoolChunk;
+ ai->Addr.Block.block_desc = "block";
+ ai->Addr.Block.block_szB = mc->szB;
+ ai->Addr.Block.rwoffset = (Int)a - (Int)mc->data;
+ ai->Addr.Block.lastchange = mc->where;
return True;
}
}
}
- ai->akind = Mempool;
- ai->blksize = cgbs[i].size;
- ai->rwoffset = (Int)(a) - (Int)(cgbs[i].start);
- ai->lastchange = cgbs[i].where;
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_Mempool;
+ ai->Addr.Block.block_desc = "mempool";
+ ai->Addr.Block.block_szB = cgbs[i].size;
+ ai->Addr.Block.rwoffset = (Int)(a) - (Int)(cgbs[i].start);
+ ai->Addr.Block.lastchange = cgbs[i].where;
return True;
}
- ai->akind = UserG;
- ai->blksize = cgbs[i].size;
- ai->rwoffset = (Int)(a) - (Int)(cgbs[i].start);
- ai->lastchange = cgbs[i].where;
- ai->desc = cgbs[i].desc;
+ ai->tag = Addr_Block;
+ ai->Addr.Block.block_kind = Block_UserG;
+ ai->Addr.Block.block_desc = cgbs[i].desc;
+ ai->Addr.Block.block_szB = cgbs[i].size;
+ ai->Addr.Block.rwoffset = (Int)(a) - (Int)(cgbs[i].start);
+ ai->Addr.Block.lastchange = cgbs[i].where;
return True;
}
}
case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
if (!ok)
- mc_record_user_error ( tid, bad_addr, /*isWrite*/True,
- /*isUnaddr*/True );
+ mc_record_user_error ( tid, bad_addr, /*isAddrErr*/True );
*ret = ok ? (UWord)NULL : bad_addr;
break;
MC_ReadResult res;
res = is_mem_defined ( arg[1], arg[2], &bad_addr );
if (MC_AddrErr == res)
- mc_record_user_error ( tid, bad_addr, /*isWrite*/False,
- /*isUnaddr*/True );
+ mc_record_user_error ( tid, bad_addr, /*isAddrErr*/True );
else if (MC_ValueErr == res)
- mc_record_user_error ( tid, bad_addr, /*isWrite*/False,
- /*isUnaddr*/False );
+ mc_record_user_error ( tid, bad_addr, /*isAddrErr*/False );
*ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
break;
}
break;
case VG_USERREQ__GET_VBITS:
- /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
- error. */
- /* VG_(printf)("get_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
*ret = mc_get_or_set_vbits_for_client
( tid, arg[1], arg[2], arg[3], False /* get them */ );
break;
case VG_USERREQ__SET_VBITS:
- /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
- error. */
- /* VG_(printf)("set_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
*ret = mc_get_or_set_vbits_for_client
( tid, arg[1], arg[2], arg[3], True /* set them */ );
break;
}
case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
- Char* s = (Char*) arg[1];
- OverlapExtra* extra = (OverlapExtra*)arg[2];
- mc_record_overlap_error(tid, s, extra);
+ Char* s = (Char*)arg[1];
+ Addr dst = (Addr) arg[2];
+ Addr src = (Addr) arg[3];
+ SizeT len = (SizeT)arg[4];
+ mc_record_overlap_error(tid, s, src, dst, len);
return True;
}
if (freed_list_end == NULL) {
tl_assert(freed_list_start == NULL);
freed_list_end = freed_list_start = mc;
- freed_list_volume = mc->size;
+ freed_list_volume = mc->szB;
} else {
tl_assert(freed_list_end->next == NULL);
freed_list_end->next = mc;
freed_list_end = mc;
- freed_list_volume += mc->size;
+ freed_list_volume += mc->szB;
}
mc->next = NULL;
tl_assert(freed_list_end != NULL);
mc1 = freed_list_start;
- freed_list_volume -= mc1->size;
+ freed_list_volume -= mc1->szB;
/* VG_(printf)("volume now %d\n", freed_list_volume); */
tl_assert(freed_list_volume >= 0);
/* Allocate its shadow chunk, put it on the appropriate list. */
static
-MC_Chunk* create_MC_Chunk ( ThreadId tid, Addr p, SizeT size,
+MC_Chunk* create_MC_Chunk ( ThreadId tid, Addr p, SizeT szB,
MC_AllocKind kind)
{
MC_Chunk* mc = VG_(malloc)(sizeof(MC_Chunk));
mc->data = p;
- mc->size = size;
+ mc->szB = szB;
mc->allockind = kind;
mc->where = VG_(record_ExeContext)(tid);
/* Allocate memory and note change in memory available */
__inline__
void* MC_(new_block) ( ThreadId tid,
- Addr p, SizeT size, SizeT align, UInt rzB,
+ Addr p, SizeT szB, SizeT alignB, UInt rzB,
Bool is_zeroed, MC_AllocKind kind, VgHashTable table)
{
cmalloc_n_mallocs ++;
tl_assert(MC_AllocCustom == kind);
} else {
tl_assert(MC_AllocCustom != kind);
- p = (Addr)VG_(cli_malloc)( align, size );
+ p = (Addr)VG_(cli_malloc)( alignB, szB );
if (!p) {
return NULL;
}
- if (is_zeroed) VG_(memset)((void*)p, 0, size);
+ if (is_zeroed) VG_(memset)((void*)p, 0, szB);
}
// Only update this stat if allocation succeeded.
- cmalloc_bs_mallocd += size;
+ cmalloc_bs_mallocd += szB;
- VG_(HT_add_node)( table, create_MC_Chunk(tid, p, size, kind) );
+ VG_(HT_add_node)( table, create_MC_Chunk(tid, p, szB, kind) );
if (is_zeroed)
- MC_(make_mem_defined)( p, size );
+ MC_(make_mem_defined)( p, szB );
else
- MC_(make_mem_undefined)( p, size );
+ MC_(make_mem_undefined)( p, szB );
return (void*)p;
}
}
}
-void* MC_(memalign) ( ThreadId tid, SizeT align, SizeT n )
+void* MC_(memalign) ( ThreadId tid, SizeT alignB, SizeT n )
{
if (complain_about_silly_args(n, "memalign")) {
return NULL;
} else {
- return MC_(new_block) ( tid, 0, n, align,
+ return MC_(new_block) ( tid, 0, n, alignB,
MC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MC_AllocMalloc,
MC_(malloc_list));
}
{
/* Note: make redzones noaccess again -- just in case user made them
accessible with a client request... */
- MC_(make_mem_noaccess)( mc->data-rzB, mc->size + 2*rzB );
+ MC_(make_mem_noaccess)( mc->data-rzB, mc->szB + 2*rzB );
/* Put it out of harm's way for a while, if not from a client request */
if (MC_AllocCustom != mc->allockind) {
} else {
/* check if it is a matching free() / delete / delete [] */
if (kind != mc->allockind) {
- MC_(record_freemismatch_error) ( tid, p, mc );
+ tl_assert(p == mc->data);
+ MC_(record_freemismatch_error) ( tid, mc );
}
die_and_free_mem ( tid, mc, rzB );
}
tid, (Addr)p, MC_MALLOC_REDZONE_SZB, MC_AllocNewVec);
}
-void* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_size )
+void* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_szB )
{
MC_Chunk* mc;
void* p_new;
- SizeT old_size;
+ SizeT old_szB;
cmalloc_n_frees ++;
cmalloc_n_mallocs ++;
- cmalloc_bs_mallocd += new_size;
+ cmalloc_bs_mallocd += new_szB;
- if (complain_about_silly_args(new_size, "realloc"))
+ if (complain_about_silly_args(new_szB, "realloc"))
return NULL;
/* Remove the old block */
/* check if its a matching free() / delete / delete [] */
if (MC_AllocMalloc != mc->allockind) {
/* can not realloc a range that was allocated with new or new [] */
- MC_(record_freemismatch_error) ( tid, (Addr)p_old, mc );
+ tl_assert((Addr)p_old == mc->data);
+ MC_(record_freemismatch_error) ( tid, mc );
/* but keep going anyway */
}
- old_size = mc->size;
+ old_szB = mc->szB;
- if (old_size == new_size) {
+ if (old_szB == new_szB) {
/* size unchanged */
mc->where = VG_(record_ExeContext)(tid);
p_new = p_old;
- } else if (old_size > new_size) {
+ } else if (old_szB > new_szB) {
/* new size is smaller */
- MC_(make_mem_noaccess)( mc->data+new_size, mc->size-new_size );
- mc->size = new_size;
+ MC_(make_mem_noaccess)( mc->data+new_szB, mc->szB-new_szB );
+ mc->szB = new_szB;
mc->where = VG_(record_ExeContext)(tid);
p_new = p_old;
} else {
/* new size is bigger */
/* Get new memory */
- Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
+ Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
if (a_new) {
/* First half kept and copied, second half new, red zones as normal */
MC_(make_mem_noaccess)( a_new-MC_MALLOC_REDZONE_SZB, MC_MALLOC_REDZONE_SZB );
- MC_(copy_address_range_state)( (Addr)p_old, a_new, mc->size );
- MC_(make_mem_undefined)( a_new+mc->size, new_size-mc->size );
- MC_(make_mem_noaccess) ( a_new+new_size, MC_MALLOC_REDZONE_SZB );
+ MC_(copy_address_range_state)( (Addr)p_old, a_new, mc->szB );
+ MC_(make_mem_undefined)( a_new+mc->szB, new_szB-mc->szB );
+ MC_(make_mem_noaccess) ( a_new+new_szB, MC_MALLOC_REDZONE_SZB );
/* Copy from old to new */
- VG_(memcpy)((void*)a_new, p_old, mc->size);
+ VG_(memcpy)((void*)a_new, p_old, mc->szB);
/* Free old memory */
/* Nb: we have to allocate a new MC_Chunk for the new memory rather
die_and_free_mem ( tid, mc, MC_MALLOC_REDZONE_SZB );
// Allocate a new chunk.
- mc = create_MC_Chunk( tid, a_new, new_size, MC_AllocMalloc );
+ mc = create_MC_Chunk( tid, a_new, new_szB, MC_AllocMalloc );
}
p_new = (void*)a_new;
while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
/* Note: make redzones noaccess again -- just in case user made them
accessible with a client request... */
- MC_(make_mem_noaccess)(mc->data-mp->rzB, mc->size + 2*mp->rzB );
+ MC_(make_mem_noaccess)(mc->data-mp->rzB, mc->szB + 2*mp->rzB );
}
// Destroy the chunk table
VG_(HT_destruct)(mp->chunks);
/* Sanity check -- make sure they don't overlap */
for (i = 0; i < n_chunks-1; i++) {
- if (chunks[i]->data + chunks[i]->size > chunks[i+1]->data ) {
+ if (chunks[i]->data + chunks[i]->szB > chunks[i+1]->data ) {
VG_(message)(Vg_UserMsg,
"Mempool chunk %d / %d overlaps with its successor",
i+1, n_chunks);
"Mempool chunk %d / %d: %d bytes [%x,%x), allocated:",
i+1,
n_chunks,
- chunks[i]->size,
+ chunks[i]->szB,
chunks[i]->data,
- chunks[i]->data + chunks[i]->size);
+ chunks[i]->data + chunks[i]->szB);
VG_(pp_ExeContext)(chunks[i]->where);
}
VG_(free)(chunks);
}
-void MC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
+void MC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT szB)
{
MC_Mempool* mp;
if (VG_(clo_verbosity) > 2) {
- VG_(message)(Vg_UserMsg, "mempool_alloc(%p, %p, %d)", pool, addr, size);
+ VG_(message)(Vg_UserMsg, "mempool_alloc(%p, %p, %d)", pool, addr, szB);
VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
}
MC_(record_illegal_mempool_error) ( tid, pool );
} else {
check_mempool_sane(mp);
- MC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zeroed,
+ MC_(new_block)(tid, addr, szB, /*ignored*/0, mp->rzB, mp->is_zeroed,
MC_AllocCustom, mp->chunks);
check_mempool_sane(mp);
}
if (VG_(clo_verbosity) > 2) {
VG_(message)(Vg_UserMsg,
"mempool_free(%p, %p) freed chunk of %d bytes",
- pool, addr, mc->size);
+ pool, addr, mc->szB);
}
die_and_free_mem ( tid, mc, mp->rzB );
}
-void MC_(mempool_trim)(Addr pool, Addr addr, SizeT size)
+void MC_(mempool_trim)(Addr pool, Addr addr, SizeT szB)
{
MC_Mempool* mp;
MC_Chunk* mc;
VgHashNode** chunks;
if (VG_(clo_verbosity) > 2) {
- VG_(message)(Vg_UserMsg, "mempool_trim(%p, %p, %d)", pool, addr, size);
+ VG_(message)(Vg_UserMsg, "mempool_trim(%p, %p, %d)", pool, addr, szB);
VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
}
mc = (MC_Chunk*) chunks[i];
lo = mc->data;
- hi = mc->size == 0 ? mc->data : mc->data + mc->size - 1;
+ hi = mc->szB == 0 ? mc->data : mc->data + mc->szB - 1;
-#define EXTENT_CONTAINS(x) ((addr <= (x)) && ((x) < addr + size))
+#define EXTENT_CONTAINS(x) ((addr <= (x)) && ((x) < addr + szB))
if (EXTENT_CONTAINS(lo) && EXTENT_CONTAINS(hi)) {
lo = mc->data;
}
- if (mc->data + size > addr + size) {
- max = mc->data + size;
- hi = addr + size;
+ if (mc->data + szB > addr + szB) {
+ max = mc->data + szB;
+ hi = addr + szB;
} else {
- max = addr + size;
- hi = mc->data + size;
+ max = addr + szB;
+ hi = mc->data + szB;
}
tl_assert(min <= lo);
}
mc->data = lo;
- mc->size = (UInt) (hi - lo);
+ mc->szB = (UInt) (hi - lo);
VG_(HT_add_node)( mp->chunks, mc );
}
VG_(HT_add_node)( MC_(mempool_list), mp );
}
-void MC_(mempool_change)(Addr pool, Addr addrA, Addr addrB, SizeT size)
+void MC_(mempool_change)(Addr pool, Addr addrA, Addr addrB, SizeT szB)
{
MC_Mempool* mp;
MC_Chunk* mc;
if (VG_(clo_verbosity) > 2) {
VG_(message)(Vg_UserMsg, "mempool_change(%p, %p, %p, %d)",
- pool, addrA, addrB, size);
+ pool, addrA, addrB, szB);
VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
}
}
mc->data = addrB;
- mc->size = size;
+ mc->szB = szB;
VG_(HT_add_node)( mp->chunks, mc );
check_mempool_sane(mp);
VG_(HT_ResetIter)(MC_(malloc_list));
while ( (mc = VG_(HT_Next)(MC_(malloc_list))) ) {
nblocks++;
- nbytes += mc->size;
+ nbytes += mc->szB;
}
VG_(message)(Vg_UserMsg,