mirror of
https://git.savannah.gnu.org/git/gperf.git
synced 2025-12-02 13:09:22 +00:00
Fix memory leaks.
This commit is contained in:
15
ChangeLog
15
ChangeLog
@@ -1,5 +1,20 @@
|
|||||||
2002-11-10 Bruno Haible <bruno@clisp.org>
|
2002-11-10 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
|
Fix memory leaks.
|
||||||
|
* src/keyword.h (empty_string): New declaration.
|
||||||
|
* src/keyword.cc (empty_string): New variable.
|
||||||
|
* src/input.h (Input::_input): Make public.
|
||||||
|
(Input::_input_end): New field.
|
||||||
|
* src/input.cc (read_input): When removing leading whitespace from
|
||||||
|
struct_decl, reallocate it. For rest, use empty_string instead of "".
|
||||||
|
Set _input_end.
|
||||||
|
(Input::~Input): Delete _struct_decl, _struct_tag, _return_type.
|
||||||
|
* src/search.cc (Search::prepare): When removing an element from
|
||||||
|
the keyword list, delete the list node.
|
||||||
|
(Search::~Search): Delete _occurrences, _asso_values.
|
||||||
|
* src/main.cc (main): Between Search::~Search and Input::~Input,
|
||||||
|
destroy the keyword list.
|
||||||
|
|
||||||
Rewrite the input routines.
|
Rewrite the input routines.
|
||||||
* src/input.h: Don't include read-line.h.
|
* src/input.h: Don't include read-line.h.
|
||||||
(Input): Don't inherit from class Read_Line.
|
(Input): Don't inherit from class Read_Line.
|
||||||
|
|||||||
54
src/input.cc
54
src/input.cc
@@ -299,9 +299,19 @@ Input::read_input ()
|
|||||||
if (struct_decl)
|
if (struct_decl)
|
||||||
{
|
{
|
||||||
/* Drop leading whitespace. */
|
/* Drop leading whitespace. */
|
||||||
while (struct_decl[0] == '\n' || struct_decl[0] == ' '
|
{
|
||||||
|| struct_decl[0] == '\t')
|
char *p = struct_decl;
|
||||||
struct_decl++;
|
while (p[0] == '\n' || p[0] == ' ' || p[0] == '\t')
|
||||||
|
p++;
|
||||||
|
if (p != struct_decl)
|
||||||
|
{
|
||||||
|
size_t len = strlen (p);
|
||||||
|
char *new_struct_decl = new char[len + 1];
|
||||||
|
memcpy (new_struct_decl, p, len + 1);
|
||||||
|
delete[] struct_decl;
|
||||||
|
struct_decl = new_struct_decl;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Drop trailing whitespace. */
|
/* Drop trailing whitespace. */
|
||||||
for (char *p = struct_decl + strlen (struct_decl); p > struct_decl;)
|
for (char *p = struct_decl + strlen (struct_decl); p > struct_decl;)
|
||||||
if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t')
|
if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t')
|
||||||
@@ -315,20 +325,19 @@ Input::read_input ()
|
|||||||
" for option --struct-type\n");
|
" for option --struct-type\n");
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
if (struct_decl)
|
{
|
||||||
{
|
/* Ensure trailing semicolon. */
|
||||||
/* Ensure trailing semicolon. */
|
size_t old_len = strlen (struct_decl);
|
||||||
size_t old_len = strlen (struct_decl);
|
if (struct_decl[old_len - 1] != ';')
|
||||||
if (struct_decl[old_len - 1] != ';')
|
{
|
||||||
{
|
char *new_struct_decl = new char[old_len + 2];
|
||||||
char *new_struct_decl = new char[old_len + 2];
|
memcpy (new_struct_decl, struct_decl, old_len);
|
||||||
memcpy (new_struct_decl, struct_decl, old_len);
|
new_struct_decl[old_len] = ';';
|
||||||
new_struct_decl[old_len] = ';';
|
new_struct_decl[old_len + 1] = '\0';
|
||||||
new_struct_decl[old_len + 1] = '\0';
|
delete[] struct_decl;
|
||||||
delete[] struct_decl;
|
struct_decl = new_struct_decl;
|
||||||
struct_decl = new_struct_decl;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* Set _struct_decl to the entire declaration. */
|
/* Set _struct_decl to the entire declaration. */
|
||||||
_struct_decl = struct_decl;
|
_struct_decl = struct_decl;
|
||||||
/* Set _struct_tag to the naked "struct something". */
|
/* Set _struct_tag to the naked "struct something". */
|
||||||
@@ -529,7 +538,7 @@ Input::read_input ()
|
|||||||
rest = line_rest;
|
rest = line_rest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rest = "";
|
rest = empty_string;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -541,7 +550,7 @@ Input::read_input ()
|
|||||||
{
|
{
|
||||||
keyword = line;
|
keyword = line;
|
||||||
keyword_length = lp - line;
|
keyword_length = lp - line;
|
||||||
rest = "";
|
rest = empty_string;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (strchr (delimiters, *lp) != NULL)
|
if (strchr (delimiters, *lp) != NULL)
|
||||||
@@ -560,7 +569,7 @@ Input::read_input ()
|
|||||||
rest = line_rest;
|
rest = line_rest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rest = "";
|
rest = empty_string;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lp++;
|
lp++;
|
||||||
@@ -588,9 +597,14 @@ Input::read_input ()
|
|||||||
|
|
||||||
/* To be freed in the destructor. */
|
/* To be freed in the destructor. */
|
||||||
_input = input;
|
_input = input;
|
||||||
|
_input_end = input_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Input::~Input ()
|
Input::~Input ()
|
||||||
{
|
{
|
||||||
|
/* Free allocated memory. */
|
||||||
|
delete[] _return_type;
|
||||||
|
delete[] _struct_tag;
|
||||||
|
delete[] _struct_decl;
|
||||||
delete[] _input;
|
delete[] _input;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,10 @@ private:
|
|||||||
FILE * _stream;
|
FILE * _stream;
|
||||||
/* Creates the keywords. */
|
/* Creates the keywords. */
|
||||||
Keyword_Factory * const _factory;
|
Keyword_Factory * const _factory;
|
||||||
|
public:
|
||||||
/* Memory block containing the entire input. */
|
/* Memory block containing the entire input. */
|
||||||
char * _input;
|
char * _input;
|
||||||
public:
|
char * _input_end;
|
||||||
/* The C code from the declarations section. */
|
/* The C code from the declarations section. */
|
||||||
const char * _verbatim_declarations;
|
const char * _verbatim_declarations;
|
||||||
const char * _verbatim_declarations_end;
|
const char * _verbatim_declarations_end;
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ Keyword_Factory::~Keyword_Factory ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
char empty_string[1] = "";
|
||||||
|
|
||||||
|
|
||||||
#ifndef __OPTIMIZE__
|
#ifndef __OPTIMIZE__
|
||||||
|
|
||||||
#define INLINE /* not inline */
|
#define INLINE /* not inline */
|
||||||
|
|||||||
@@ -86,11 +86,14 @@ public:
|
|||||||
virtual ~Keyword_Factory ();
|
virtual ~Keyword_Factory ();
|
||||||
|
|
||||||
/* Creates a new Keyword. */
|
/* Creates a new Keyword. */
|
||||||
virtual /*abstract */ Keyword *
|
virtual /*abstract*/ Keyword *
|
||||||
create_keyword (const char *allchars, int allchars_length,
|
create_keyword (const char *allchars, int allchars_length,
|
||||||
const char *rest) = 0;
|
const char *rest) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A statically allocated empty string. */
|
||||||
|
extern char empty_string[1];
|
||||||
|
|
||||||
#ifdef __OPTIMIZE__
|
#ifdef __OPTIMIZE__
|
||||||
|
|
||||||
#define INLINE inline
|
#define INLINE inline
|
||||||
|
|||||||
109
src/main.cc
109
src/main.cc
@@ -49,6 +49,8 @@ KeywordExt_Factory::create_keyword (const char *allchars, int allchars_length, c
|
|||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
int exitcode;
|
||||||
|
|
||||||
/* Set the Options. Open the input file and assign stdin to it. */
|
/* Set the Options. Open the input file and assign stdin to it. */
|
||||||
option.parse_options (argc, argv);
|
option.parse_options (argc, argv);
|
||||||
|
|
||||||
@@ -61,46 +63,79 @@ main (int argc, char *argv[])
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the keyword list. */
|
{
|
||||||
KeywordExt_Factory factory;
|
/* Initialize the keyword list. */
|
||||||
Input inputter (stdin, &factory);
|
KeywordExt_Factory factory;
|
||||||
inputter.read_input ();
|
Input inputter (stdin, &factory);
|
||||||
/* We can cast the keyword list to KeywordExt_List* because its list
|
inputter.read_input ();
|
||||||
elements were created by KeywordExt_Factory. */
|
/* We can cast the keyword list to KeywordExt_List* because its list
|
||||||
KeywordExt_List* list = static_cast<KeywordExt_List*>(inputter._head);
|
elements were created by KeywordExt_Factory. */
|
||||||
|
KeywordExt_List* list = static_cast<KeywordExt_List*>(inputter._head);
|
||||||
|
|
||||||
/* Search for a good hash function. */
|
|
||||||
Search searcher (list);
|
|
||||||
searcher.optimize ();
|
|
||||||
|
|
||||||
/* Output the hash function code. */
|
|
||||||
Output outputter (searcher._head,
|
|
||||||
inputter._struct_decl,
|
|
||||||
inputter._return_type,
|
|
||||||
inputter._struct_tag,
|
|
||||||
inputter._verbatim_declarations,
|
|
||||||
inputter._verbatim_declarations_end,
|
|
||||||
inputter._verbatim_declarations_lineno,
|
|
||||||
inputter._verbatim_code,
|
|
||||||
inputter._verbatim_code_end,
|
|
||||||
inputter._verbatim_code_lineno,
|
|
||||||
searcher._total_keys,
|
|
||||||
searcher._total_duplicates,
|
|
||||||
searcher._max_key_len,
|
|
||||||
searcher._min_key_len,
|
|
||||||
searcher._alpha_size,
|
|
||||||
searcher._occurrences,
|
|
||||||
searcher._asso_values);
|
|
||||||
outputter.output ();
|
|
||||||
|
|
||||||
/* Check for write error on stdout. */
|
|
||||||
int status = 0;
|
|
||||||
if (fflush (stdout) || ferror (stdout))
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "error while writing output file\n");
|
/* Search for a good hash function. */
|
||||||
status = 1;
|
Search searcher (list);
|
||||||
|
searcher.optimize ();
|
||||||
|
list = searcher._head;
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Output the hash function code. */
|
||||||
|
Output outputter (searcher._head,
|
||||||
|
inputter._struct_decl,
|
||||||
|
inputter._return_type,
|
||||||
|
inputter._struct_tag,
|
||||||
|
inputter._verbatim_declarations,
|
||||||
|
inputter._verbatim_declarations_end,
|
||||||
|
inputter._verbatim_declarations_lineno,
|
||||||
|
inputter._verbatim_code,
|
||||||
|
inputter._verbatim_code_end,
|
||||||
|
inputter._verbatim_code_lineno,
|
||||||
|
searcher._total_keys,
|
||||||
|
searcher._total_duplicates,
|
||||||
|
searcher._max_key_len,
|
||||||
|
searcher._min_key_len,
|
||||||
|
searcher._alpha_size,
|
||||||
|
searcher._occurrences,
|
||||||
|
searcher._asso_values);
|
||||||
|
outputter.output ();
|
||||||
|
|
||||||
|
/* Check for write error on stdout. */
|
||||||
|
exitcode = 0;
|
||||||
|
if (fflush (stdout) || ferror (stdout))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "error while writing output file\n");
|
||||||
|
exitcode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here we run the Output destructor. */
|
||||||
|
}
|
||||||
|
/* Here we run the Search destructor. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Also delete the list that was allocated inside Input and reordered
|
||||||
|
inside Search. */
|
||||||
|
for (KeywordExt_List *ptr = list; ptr; ptr = ptr->rest())
|
||||||
|
{
|
||||||
|
KeywordExt *keyword = ptr->first();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
KeywordExt *next_keyword = keyword->_duplicate_link;
|
||||||
|
delete[] keyword->_selchars;
|
||||||
|
if (keyword->_rest != empty_string)
|
||||||
|
delete[] keyword->_rest;
|
||||||
|
if (!(keyword->_allchars >= inputter._input
|
||||||
|
&& keyword->_allchars < inputter._input_end))
|
||||||
|
delete[] keyword->_allchars;
|
||||||
|
delete keyword;
|
||||||
|
keyword = next_keyword;
|
||||||
|
}
|
||||||
|
while (keyword != NULL);
|
||||||
|
}
|
||||||
|
delete_list (list);
|
||||||
|
|
||||||
|
/* Here we run the Input destructor. */
|
||||||
|
}
|
||||||
|
|
||||||
/* Don't use exit() here, it skips the destructors. */
|
/* Don't use exit() here, it skips the destructors. */
|
||||||
return status;
|
return exitcode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,10 +94,11 @@ Search::prepare ()
|
|||||||
Hash_Table representatives (_list_len, option[NOLENGTH]);
|
Hash_Table representatives (_list_len, option[NOLENGTH]);
|
||||||
|
|
||||||
KeywordExt_List *prev = NULL; /* list node before temp */
|
KeywordExt_List *prev = NULL; /* list node before temp */
|
||||||
for (temp = _head; temp; temp = temp->rest())
|
for (temp = _head; temp; )
|
||||||
{
|
{
|
||||||
KeywordExt *keyword = temp->first();
|
KeywordExt *keyword = temp->first();
|
||||||
KeywordExt *other_keyword = representatives.insert (keyword);
|
KeywordExt *other_keyword = representatives.insert (keyword);
|
||||||
|
KeywordExt_List *garbage = NULL;
|
||||||
|
|
||||||
if (other_keyword)
|
if (other_keyword)
|
||||||
{
|
{
|
||||||
@@ -105,6 +106,7 @@ Search::prepare ()
|
|||||||
_list_len--;
|
_list_len--;
|
||||||
/* Remove keyword from the main list. */
|
/* Remove keyword from the main list. */
|
||||||
prev->rest() = temp->rest();
|
prev->rest() = temp->rest();
|
||||||
|
garbage = temp;
|
||||||
/* And insert it on other_keyword's duplicate list. */
|
/* And insert it on other_keyword's duplicate list. */
|
||||||
keyword->_duplicate_link = other_keyword->_duplicate_link;
|
keyword->_duplicate_link = other_keyword->_duplicate_link;
|
||||||
other_keyword->_duplicate_link = keyword;
|
other_keyword->_duplicate_link = keyword;
|
||||||
@@ -121,6 +123,9 @@ Search::prepare ()
|
|||||||
keyword->_duplicate_link = NULL;
|
keyword->_duplicate_link = NULL;
|
||||||
prev = temp;
|
prev = temp;
|
||||||
}
|
}
|
||||||
|
temp = temp->rest();
|
||||||
|
if (garbage)
|
||||||
|
delete garbage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,4 +803,6 @@ Search::~Search ()
|
|||||||
|
|
||||||
fprintf (stderr, "End dumping list.\n\n");
|
fprintf (stderr, "End dumping list.\n\n");
|
||||||
}
|
}
|
||||||
|
delete[] _asso_values;
|
||||||
|
delete[] _occurrences;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ SHELL = /bin/sh
|
|||||||
VPATH = $(srcdir)
|
VPATH = $(srcdir)
|
||||||
|
|
||||||
GPERF = ../src/gperf
|
GPERF = ../src/gperf
|
||||||
|
#GPERF = valgrind --num-callers=20 --leak-check=yes --leak-resolution=high --show-reachable=yes ../src/gperf
|
||||||
|
|
||||||
all :
|
all :
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user