⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dmalloc.c

📁 减少内存碎片的malloc分配函数
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * program that handles the dmalloc variables. * * Copyright 2000 by Gray Watson * * This file is part of the dmalloc package. * * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies, and that the name of Gray Watson not be used in advertising * or publicity pertaining to distribution of the document or software * without specific, written prior permission. * * Gray Watson makes no representations about the suitability of the * software described herein for any purpose.  It is provided "as is" * without express or implied warranty. * * The author may be contacted via http://dmalloc.com/ * * $Id: dmalloc.c,v 1.114 2004/07/10 03:49:52 gray Exp $ *//* * This is the dmalloc program which is designed to enable the user to * easily set the environmental variables that control the dmalloc * library capabilities. *//* * NOTE: all standard-output from this program is designed to be run * through a shell evaluation command by default.  Any messages for * the user should therefore be send to stderr. */#include <stdio.h>				/* for stderr */#define DMALLOC_DISABLE#include "dmalloc_argv.h"			/* for argument processing */#if HAVE_STRING_H# include <string.h>#endif#if HAVE_STDLIB_H# include <stdlib.h>#endif#include "conf.h"#include "dmalloc.h"#include "compat.h"#include "debug_tok.h"#include "debug_tok.h"#include "env.h"#include "error_val.h"#include "dmalloc_loc.h"#include "version.h"#define HOME_ENVIRON	"HOME"			/* home directory */#define SHELL_ENVIRON	"SHELL"			/* for the type of shell */#define DEFAULT_CONFIG	".dmallocrc"		/* default config file */#define TOKENIZE_EQUALS	" \t="			/* for tag lines */#define TOKENIZE_CHARS	" \t,"			/* for tag lines */#define DEBUG_ARG		'd'		/* debug argument */#define INTERVAL_ARG		'i'		/* interval argument */#define THREAD_LOCK_ON_ARG	'o'		/* lock-on argument */#define LIMIT_ARG		'M'		/* memory-limit argument */#define LINE_WIDTH		75		/* num debug toks per line */#define FILE_NOT_FOUND		1#define FILE_FOUND		2#define TOKEN_FOUND		3/* * default flag information */typedef struct {  char		*de_string;			/* default name */  long		de_flags;			/* default settings */} default_t;#define RUNTIME_FLAGS	(DEBUG_LOG_STATS | DEBUG_LOG_NONFREE | \			 DEBUG_LOG_BAD_SPACE | \			 DEBUG_CHECK_FENCE | \			 DEBUG_CATCH_NULL)#define LOW_FLAGS	(RUNTIME_FLAGS | \			 DEBUG_LOG_ELAPSED_TIME | \			 DEBUG_CHECK_SHUTDOWN | \			 DEBUG_FREE_BLANK | DEBUG_ERROR_ABORT | \			 DEBUG_ALLOC_BLANK)#define MEDIUM_FLAGS	(LOW_FLAGS | \			 DEBUG_CHECK_HEAP | \			 DEBUG_REALLOC_COPY)#define HIGH_FLAGS	(MEDIUM_FLAGS | \			 DEBUG_CHECK_BLANK | DEBUG_CHECK_FUNCS)#define ALL_FLAGS	(HIGH_FLAGS | \			 DEBUG_LOG_TRANS | DEBUG_LOG_ADMIN | \			 DEBUG_NEVER_REUSE)/* NOTE: print-messages is not in this list because it is special */static	default_t	defaults[] = {  { "none",		0 },  { "runtime",		RUNTIME_FLAGS },  { "run",		RUNTIME_FLAGS },  { "low",		LOW_FLAGS },  { "med",		MEDIUM_FLAGS },  { "medium",		MEDIUM_FLAGS },  { "high",		HIGH_FLAGS },  { "all",		ALL_FLAGS },  { NULL }};/* argument variables */static	int	bourne_b = 0;			/* set bourne shell output */static	int	cshell_b = 0;			/* set c-shell output */static	int	gdb_b = 0;			/* set gdb output */static	int	rcshell_b = 0;			/* set rc shell output */static	char	*address = NULL;		/* for ADDRESS */static	int	clear_b = 0;			/* clear variables */static	int	debug = 0;			/* for DEBUG */static	int	errno_to_print = 0;		/* to print the error string */static	int	help_b = 0;			/* print help message */static	char	*inpath = NULL;			/* for config-file path */static	unsigned long interval = 0;		/* for setting INTERVAL */static	int	thread_lock_on = 0;		/* for setting LOCK_ON */static	int	keep_b = 0;			/* keep settings override -r */static	int	list_tags_b = 0;		/* list rc tags */static	int	debug_tokens_b = 0;		/* list debug tokens */static	char	*logpath = NULL;		/* for LOGFILE setting */static	int	long_tokens_b = 0;		/* long-tok output */static	argv_array_t	minus;			/* tokens to remove */static	unsigned long limit_arg = 0;		/* memory limit */static	int	make_changes_b = 1;		/* make no changes to env */static	argv_array_t	plus;			/* tokens to add */static	int	remove_auto_b = 0;		/* auto-remove settings */static	char	*start_file = NULL;		/* for START settings */static	unsigned long start_iter = 0;		/* for START settings */static	unsigned long start_size = 0;		/* for START settings */static	int	usage_b = 0;			/* usage messages */static	int	verbose_b = 0;			/* verbose flag */static	int	very_verbose_b = 0;		/* very-verbose flag */static	char	*tag = NULL;			/* maybe a tag argument */static	argv_t	args[] = {  { 'b',	"bourne-shell",	ARGV_BOOL_INT,	&bourne_b,    NULL,			"set output for bourne shells" },  { ARGV_OR },  { 'C',	"c-shell",	ARGV_BOOL_INT,	&cshell_b,    NULL,			"set output for C-type shells" },  { ARGV_OR },  { 'g',	"gdb",		ARGV_BOOL_INT,	&gdb_b,    NULL,			"set output for gdb parsing" },  { ARGV_OR },  { 'R',	"rc-shell",	ARGV_BOOL_INT,	&rcshell_b,    NULL,			"set output for rc shell" },    { 'L',	"long-tokens",	ARGV_BOOL_INT,	&long_tokens_b,    NULL,			"output long-tokens not 0x..." },    { 'a',	"address",	ARGV_CHAR_P,	&address,    "address:#",		"stop when malloc sees address" },  { 'c',	"clear",	ARGV_BOOL_INT,	&clear_b,    NULL,			"clear all variables not set" },  { DEBUG_ARG,	"debug-mask",	ARGV_HEX,	&debug,    "value",			"hex flag to set debug mask" },  { 'D',	"debug-tokens",	ARGV_BOOL_INT,	&debug_tokens_b,    NULL,			"list debug tokens" },  { 'e',	"errno",	ARGV_INT,	&errno_to_print,    "errno",			"print error string for errno" },  { 'f',	"file",		ARGV_CHAR_P,	&inpath,    "path",			"config if not $HOME/.dmallocrc" },  { 'h',	"help",		ARGV_BOOL_INT,	&help_b,    NULL,			"print help message" },  { INTERVAL_ARG, "interval",	ARGV_U_LONG,	&interval,    "value",			"check heap every number times" },  { 'k',	"keep",		ARGV_BOOL_INT,	&keep_b,    NULL,			"keep settings (override -r)" },  { 'l',	"logfile",	ARGV_CHAR_P,	&logpath,    "path",			"file to log messages to" },  { 'm',	"minus",	ARGV_CHAR_P | ARGV_FLAG_ARRAY,	&minus,    "token(s)",			"del tokens from current debug" },  { LIMIT_ARG,	"memory-limit",	ARGV_U_SIZE,	&limit_arg,    "value",			"limit allocations to this amount" },  { 'n',	"no-changes",	ARGV_BOOL_NEG,	&make_changes_b,    NULL,			"make no changes to the env" },  { THREAD_LOCK_ON_ARG, "lock-on", ARGV_INT,	&thread_lock_on,    "number",			"number of times to not lock" },  { 'p',	"plus",		ARGV_CHAR_P | ARGV_FLAG_ARRAY,	&plus,    "token(s)",			"add tokens to current debug" },  { 'r',	"remove",	ARGV_BOOL_INT,	&remove_auto_b,    NULL,			"remove other settings if tag" },    { 's',	"start-file",	ARGV_CHAR_P,	&start_file,    "file:line",		"check heap after this location" },  { ARGV_OR },  { 'S',	"start-iter",	ARGV_U_LONG,	&start_iter,    "number",			"check heap after this iteration" },  { ARGV_OR },  { '\0',	"start-size",	ARGV_U_SIZE,	&start_size,    "size",			"check heap after this mem size" },    { 't',	"list-tags",	ARGV_BOOL_INT,	&list_tags_b,    NULL,			"list tags in rc file" },  { 'u',	"usage",	ARGV_BOOL_INT,	&usage_b,    NULL,			"print usage messages" },  { 'v',	"verbose",	ARGV_BOOL_INT,	&verbose_b,    NULL,			"turn on verbose output" },  { 'V',	"very-verbose",	ARGV_BOOL_INT,	&very_verbose_b,    NULL,			"turn on very-verbose output" },  { ARGV_MAYBE,	NULL,		ARGV_CHAR_P,	&tag,    "tag",			"debug token to find in rc" },  { ARGV_LAST }};/* * list of bourne shells */static	char	*sh_shells[] = { "sh", "ash", "bash", "ksh", "zsh", NULL };/* * try a check out the shell env variable to see what form of shell * commands we should output */static	void	choose_shell(void){  const char	*shell, *shell_p;  int		shell_c;    shell = getenv(SHELL_ENVIRON);  if (shell == NULL) {    /* oh well, we just guess on c-shell */    cshell_b = 1;    return;  }    shell_p = strrchr(shell, '/');  if (shell_p == NULL) {    shell_p = shell;  }  else {    shell_p++;  }    /* look for the rc shell specifically */  if (strcmp("rc", shell_p) == 0) {    rcshell_b = 1;    return;  }    /* look for the shells which are bourne-shell compatible */  for (shell_c = 0; sh_shells[shell_c] != NULL; shell_c++) {    if (strcmp(sh_shells[shell_c], shell_p) == 0) {      bourne_b = 1;      return;    }  }    /* otherwise set to c-shell */  cshell_b = 1;}/* * dump the current flags set in the debug variable VAL */static	void	dump_debug(const unsigned long val){  attr_t	*attr_p;  char		*str;  unsigned long	work = val;  int		col_c = 0, len;    for (attr_p = attributes; attr_p->at_string != NULL; attr_p++) {    /* the below test for work == 0 is necessary to handle the 'none' token */    if ((work == 0 && attr_p->at_value == 0)	|| (attr_p->at_value != 0 && BIT_IS_SET(work, attr_p->at_value))) {      BIT_CLEAR(work, attr_p->at_value);            if (col_c == 0) {	(void)fprintf(stderr, "   ");	col_c += 3;      }            if (very_verbose_b) {	(void)fprintf(stderr, "%s -- %s (%#lx)\n",		      attr_p->at_string, attr_p->at_desc, attr_p->at_value);	col_c = 0;      }      else {	str = attr_p->at_string;	len = strlen(str);	if (col_c + len + 2 > LINE_WIDTH) {	  (void)fprintf(stderr, "\n");	  (void)fprintf(stderr, "   ");	  col_c = 3;	}	(void)fprintf(stderr, "%s", str);	col_c += len;		/* if we've got more to go then print the , */	if (work != 0) {	  (void)fprintf(stderr, ", ");	  col_c += 2;	}      }            if (work == 0) {	break;      }    }  }    if (col_c != 0) {    (void)fprintf(stderr, "\n");  }    if (work != 0) {    (void)fprintf(stderr, "%s: warning, unknown debug flag(s): %#lx\n",		  argv_program, work);  }}/* * translate TOK into its proper value which is returned */static	long	token_to_value(const char *tok){  attr_t	*attr_p;    /* find the matching attribute string */  for (attr_p = attributes; attr_p->at_string != NULL; attr_p++) {    if (strcmp(tok, attr_p->at_string) == 0) {      break;    }  }    if (attr_p->at_string == NULL) {    (void)fprintf(stderr, "%s: unknown token '%s'\n", argv_program, tok);    return 0;  }    /* if we have a 0 value and not none then this is a disabled token */  if (attr_p->at_value == 0 && strcmp(tok, "none") != 0) {    (void)fprintf(stderr, "%s: token '%s' has been disabled: %s\n",		  argv_program, tok, attr_p->at_desc);    return 0;  }    return attr_p->at_value;}/* * Read in the next token from INFILE.  It passes back the returned * debug value in DEBUG_P.  Passes back the matching TOKEN of * TOKEN_SIZE.  Returns 1 if there was a next else 0. */static	int	read_next_token(FILE *infile, long *debug_p,				char *token, const int token_size){  int	cont_b = 0, found_b = 0;  long	new_debug = 0;  char	buf[1024], *tok_p, *buf_p;    while (fgets(buf, sizeof(buf), infile) != NULL) {        /* ignore comments and empty lines */    if (buf[0] == '#' || buf[0] == '\n') {      continue;    }        /* chop off the ending \n */    buf_p = strrchr(buf, '\n');    SET_POINTER(buf_p, '\0');        buf_p = buf;        /* if we're not continuing then we need to process a tag */    if (! cont_b) {            /* get the first token on the line */      tok_p = strsep(&buf_p, TOKENIZE_EQUALS);      if (tok_p == NULL) {	continue;      }      if (*tok_p == '\0') {	(void)fprintf(stderr, "Invalid start of line: %s\n", buf_p);	continue;      }            /* save the token */      if (token != NULL) {	(void)strncpy(token, tok_p, token_size);	token[token_size - 1] = '\0';      }      found_b = 1;    }        cont_b = 0;        while (1) {      /* get the next token */      tok_p = strsep(&buf_p, TOKENIZE_CHARS);      if (tok_p == NULL) {	break;      }      if (*tok_p == '\0') {	continue;      }            /* do we have a continuation character? */      if (strcmp(tok_p, "\\") == 0) {	cont_b = 1;	break;      }            new_debug |= token_to_value(tok_p);    }        /* are we done? */    if (! cont_b) {      break;    }  }    SET_POINTER(debug_p, new_debug);    if (found_b) {    return 1;  }  else {    return 0;  }}/* * Read in a rc file from PATH and process it looking for the * specified DEBUG_VALUE or TAG_FIND token.  It passes back the * returned debug value in DEBUG_P.  Passes back the matching TOKEN of * TOKEN_SIZE. * * Returns FILE_NOT_FOUND, FILE_FOUND, or TOKEN_FOUND. */static	int	read_rc_file(const char *path, const long debug_value,			     const char *tag_find, long *debug_p,			     char *token, const int token_size){  FILE	*infile;  int	found_b = 0;  char	next_token[64];  long	new_debug;    /* open the path */  infile = fopen(path, "r");  if (infile == NULL) {    return FILE_NOT_FOUND;  }    /* run through the tokens, looking for a match */  while (read_next_token(infile, &new_debug, next_token,			 sizeof(next_token)) == 1) {        /* are we looking for a tag? */    if (tag_find != NULL && strcmp(tag_find, next_token) == 0) {      found_b = 1;      break;    }        /* are we looking for a debug-value? */    if (debug_value > 0 && debug_value == new_debug) {      found_b = 1;      break;    }  }    (void)fclose(infile);    SET_POINTER(debug_p, new_debug);  if (token != NULL) {    (void)loc_snprintf(token, token_size, "config file token: %s",		       next_token);  }    if (found_b) {    return TOKEN_FOUND;  }  else {    return FILE_FOUND;  }}/* * Process the user configuration looking for the TAG_FIND.  If it is * null then look for DEBUG_VALUE in the file and copy the token found * into TOKEN of TOKEN_SIZE.  Routine returns the new debug value * matching tag. */static	long	find_tag(const long debug_value, const char *tag_find,			 char *token, const int token_size){  char		path[1024], *path_p;  default_t	*def_p;  const char	*home_p;  int		ret;  long		new_debug = 0;    /* do we need to have a home variable? */  if (inpath == NULL) {        /* first we try to read the RC file from the current directory */    ret = read_rc_file(DEFAULT_CONFIG, debug_value, tag_find, &new_debug,		       token, token_size);    /* did we find the correct value in the file? */    if (ret == TOKEN_FOUND) {      return new_debug;    }        /* if we did not find the file, check the home directory */    if (ret == FILE_FOUND) {      path_p = DEFAULT_CONFIG;    }    else {      /* find our home directory */      home_p = getenv(HOME_ENVIRON);      if (home_p == NULL) {	(void)fprintf(stderr, "%s: could not find variable '%s'\n",		      argv_program, HOME_ENVIRON);	exit(1);      }            (void)loc_snprintf(path, sizeof(path), "%s/%s", home_p, DEFAULT_CONFIG);            /* read in the file from our home directory */      ret = read_rc_file(path, debug_value, tag_find, &new_debug,			 token, token_size);      /* did we find the correct value in the file? */      if (ret == TOKEN_FOUND) {	return new_debug;      }      if (ret == FILE_FOUND) {	path_p = path;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -