📄 diag.c
字号:
/* * mpatrol * A library for controlling and tracing dynamic memory allocations. * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. *//* * Diagnostics. Most of the diagnostics go to a log file which is opened * as soon as possible, but if this fails then the standard error is used. * Many of these functions also deal with the formatting and displaying of * certain data structures used by the mpatrol library. */#include "diag.h"#if MP_THREADS_SUPPORT#include "mutex.h"#endif /* MP_THREADS_SUPPORT */#include "utils.h"#include "version.h"#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <time.h>#if TARGET == TARGET_UNIX#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#endif /* TARGET */#if MP_IDENT_SUPPORT#ident "$Id: diag.c,v 1.104 2002/01/08 20:13:59 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *diag_id = "$Id: diag.c,v 1.104 2002/01/08 20:13:59 graeme Exp $";#endif /* MP_IDENT_SUPPORT */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */MP_API extern errortype __mp_errno;/* The file pointer to the log file. This should not really be a file scope * variable as it prevents this module from being re-entrant. */static FILE *logfile;/* The byte array used for file buffering purposes. Care must be taken to * ensure that this buffer is not used for more than one file and this should * not really be a file scope variable as it prevents this module from being * re-entrant. */static char buffer[256];/* The current date and time at which the log file is being created. This * must be fixed once it has been determined since it may be used in several * places. */static time_t currenttime;/* The total error and warning counts. These should really be reset after * every initialisation of the library, but as we are not currently allowing * library to be reinitialised, this doesn't matter. */static unsigned long errors, warnings;/* This array should always be kept in step with the errortype enumeration. */MP_GLOBAL errorinfo __mp_errordetails[ET_MAX + 1] ={ {"NOERR", "no error", "no error has occurred"}, {"ALLOVF", "allocation overflow", "allocation " MP_POINTER " has a corrupted overflow buffer at " MP_POINTER}, {"ALLZER", "allocation too small", "attempt to create an allocation of size 0"}, {"BADALN", "illegal alignment", "alignment %lu is not a power of two"}, {"FRDCOR", "freed memory corruption", "freed allocation " MP_POINTER " has memory corruption at " MP_POINTER}, {"FRDOPN", "illegal operation on freed memory", "attempt to perform operation on freed memory"}, {"FRDOVF", "freed allocation overflow", "freed allocation " MP_POINTER " has a corrupted overflow buffer at " MP_POINTER}, {"FRECOR", "free memory corruption", "free memory corruption at " MP_POINTER}, {"FREMRK", "freeing a marked allocation", "attempt to free marked memory allocation " MP_POINTER}, {"FRENUL", "freeing a NULL pointer", "attempt to free a NULL pointer"}, {"FREOPN", "illegal operation on free memory", "attempt to perform operation on free memory\n"}, {"ILLMEM", "illegal memory access", NULL}, {"INCOMP", "incompatible functions", MP_POINTER " was allocated with %s"}, {"MAXALN", "alignment too large", "alignment %lu is greater than the system page size"}, {"MISMAT", "allocated pointer mismatch", MP_POINTER " does not match allocation of " MP_POINTER}, {"NOTALL", "no such allocation", MP_POINTER " has not been allocated"}, {"NULOPN", "illegal operation on a NULL pointer", "attempt to perform operation on a NULL pointer\n"}, {"OUTMEM", "out of memory", "out of memory"}, {"PRVFRD", "allocation already freed", MP_POINTER " was freed with %s"}, {"RNGOVF", "range overflow", "range [" MP_POINTER "," MP_POINTER "] overflows [" MP_POINTER "," MP_POINTER "]"}, {"RNGOVL", "range overlap", "range [" MP_POINTER "," MP_POINTER "] overlaps [" MP_POINTER "," MP_POINTER "]"}, {"RSZNUL", "reallocating a NULL pointer", "attempt to resize a NULL pointer"}, {"RSZZER", "reallocation too small", "attempt to resize an allocation to size 0"}, {"STROVF", "string overflow", "string " MP_POINTER " overflows [" MP_POINTER "," MP_POINTER "]"}, {"ZERALN", "alignment too small", "alignment 0 is invalid"}, {"INTRNL", "internal error", "internal error"}};/* This array should always be kept in step with the alloctype enumeration. * Note that AT_MAX is used in diagnostic messages to specify that the * message is internal and did not come from a call to a normal memory * allocation function. */MP_GLOBAL char *__mp_functionnames[AT_MAX + 1] ={ "malloc", "calloc", "memalign", "valloc", "pvalloc", "alloca", "strdup", "strndup", "strsave", "strnsave", "strdupa", "strndupa", "realloc", "reallocf", "recalloc", "expand", "free", "cfree", "dealloca", "xmalloc", "xcalloc", "xstrdup", "xrealloc", "xfree", "operator new", "operator new[]", "operator delete", "operator delete[]", "memset", "bzero", "memccpy", "memcpy", "memmove", "bcopy", "memchr", "memmem", "memcmp", "bcmp", "check"};/* This array should always be kept in step with the logtype enumeration. * Note that LT_MAX is used to indicate that the variant field of the loginfo * structure is not used. */MP_GLOBAL char *__mp_lognames[LT_MAX + 1] ={ "ALLOC", "REALLOC", "FREE", "MEMSET", "MEMCOPY", "MEMFIND", "MEMCMP", "LOG"};/* The flags used to control the diagnostics from the mpatrol library. */MP_GLOBAL unsigned long __mp_diagflags;/* Process a file name, expanding any special characters. */staticvoidprocessfile(meminfo *m, char *s, char *b, size_t l){ char *p, *t; size_t i; for (i = 0; (i < l - 1) && (*s != '\0'); i++, s++) if (*s == '%') switch (s[1]) { case 'd': /* Replace %d with the current date in the form YYYYMMDD. */ if (!currenttime) currenttime = time(NULL); if (currenttime != (time_t) -1) strftime(b + i, l - i, "%Y%m%d", localtime(¤ttime)); else strcpy(b + i, "today"); i += strlen(b + i) - 1; s++; break; case 'f': /* Replace %f with the program filename, with all path * separation characters replaced by underscores. */ if (((p = m->prog) == NULL) || (*p == '\0')) p = "mpatrol"; while (*p != '\0') {#if TARGET == TARGET_UNIX if (*p == '/')#elif TARGET == TARGET_AMIGA if ((*p == ':') || (*p == '/'))#else /* TARGET */ if ((*p == ':') || (*p == '/') || (*p == '\\'))#endif /* TARGET */ b[i++] = '_'; else b[i++] = *p; p++; } i--; s++; break; case 'n': /* Replace %n with the current process identifier. */ sprintf(b + i, "%lu", __mp_processid()); i += strlen(b + i) - 1; s++; break; case 'p': /* Replace %p with the program name. */ if (p = m->prog)#if TARGET == TARGET_UNIX while (t = strchr(p, '/'))#elif TARGET == TARGET_AMIGA while (t = strpbrk(p, ":/"))#else /* TARGET */ while (t = strpbrk(p, ":/\\"))#endif /* TARGET */ p = t + 1; if ((p == NULL) || (*p == '\0')) p = "mpatrol"; strcpy(b + i, p); i += strlen(p) - 1; s++; break; case 't': /* Replace %t with the current time in the form HHMMSS. */ if (!currenttime) currenttime = time(NULL); if (currenttime != (time_t) -1) strftime(b + i, l - i, "%H%M%S", localtime(¤ttime)); else strcpy(b + i, "now"); i += strlen(b + i) - 1; s++; break; default: if (s[1] != '\0') b[i++] = *s++; b[i] = *s; break; } else b[i] = *s; b[i] = '\0';}/* Process the log file name, expanding any special characters. * Note that this function is not currently re-entrant. */MP_GLOBALchar *__mp_logfile(meminfo *m, char *s){ static char b[256]; char p[256]; char *d; if ((s != NULL) && ((strcmp(s, "stderr") == 0) || (strcmp(s, "stdout") == 0))) return s; if ((d = getenv(MP_LOGDIR)) && (*d != '\0') && ((s == NULL) ||#if TARGET == TARGET_UNIX !strchr(s, '/')))#elif TARGET == TARGET_AMIGA !strpbrk(s, ":/")))#else /* TARGET */ !strpbrk(s, ":/\\")))#endif /* TARGET */ { /* If the environment variable specified with MP_LOGDIR is set and no * log file name has already been given then we use a special format * for the name of the output file so that all such files will be * written to that directory, which must exist. */ if (s == NULL) s = "%n.%p.log";#if TARGET == TARGET_UNIX sprintf(p, "%s/%s", d, s);#elif TARGET == TARGET_AMIGA if ((d[strlen(d) - 1] == ':') || (d[strlen(d) - 1] == '/')) sprintf(p, "%s%s", d, s); else sprintf(p, "%s/%s", d, s);#else /* TARGET */ sprintf(p, "%s\\%s", d, s);#endif /* TARGET */ processfile(m, p, b, sizeof(b)); } else { if (s == NULL) s = MP_LOGFILE; processfile(m, s, b, sizeof(b)); } return b;}/* Process the profiling output file name, expanding any special characters. * Note that this function is not currently re-entrant. */MP_GLOBALchar *__mp_proffile(meminfo *m, char *s){ static char b[256]; char p[256]; char *d; if ((s != NULL) && ((strcmp(s, "stderr") == 0) || (strcmp(s, "stdout") == 0))) return s; if ((d = getenv(MP_PROFDIR)) && (*d != '\0') && ((s == NULL) ||#if TARGET == TARGET_UNIX !strchr(s, '/')))#elif TARGET == TARGET_AMIGA !strpbrk(s, ":/")))#else /* TARGET */ !strpbrk(s, ":/\\")))#endif /* TARGET */ { /* If the environment variable specified with MP_PROFDIR is set and no * profiling output file name has already been given then we use a * special format for the name of the output file so that all such * files will be written to that directory, which must exist. */ if (s == NULL) s = "%n.%p.out";#if TARGET == TARGET_UNIX sprintf(p, "%s/%s", d, s);#elif TARGET == TARGET_AMIGA if ((d[strlen(d) - 1] == ':') || (d[strlen(d) - 1] == '/')) sprintf(p, "%s%s", d, s); else sprintf(p, "%s/%s", d, s);#else /* TARGET */ sprintf(p, "%s\\%s", d, s);#endif /* TARGET */ processfile(m, p, b, sizeof(b)); } else { if (s == NULL) s = MP_PROFFILE; processfile(m, s, b, sizeof(b)); } return b;}/* Process the tracing output file name, expanding any special characters. * Note that this function is not currently re-entrant. */MP_GLOBALchar *__mp_tracefile(meminfo *m, char *s){ static char b[256]; char p[256]; char *d; if ((s != NULL) && ((strcmp(s, "stderr") == 0) || (strcmp(s, "stdout") == 0))) return s; if ((d = getenv(MP_TRACEDIR)) && (*d != '\0') && ((s == NULL) ||#if TARGET == TARGET_UNIX !strchr(s, '/')))#elif TARGET == TARGET_AMIGA !strpbrk(s, ":/")))#else /* TARGET */ !strpbrk(s, ":/\\")))#endif /* TARGET */ { /* If the environment variable specified with MP_TRACEDIR is set and no * tracing output file name has already been given then we use a * special format for the name of the output file so that all such * files will be written to that directory, which must exist. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -