Memory-management cleanup in make-docfile
I compiled it with -fsanitize=address and fixed the leaks it detected. Also, I changed it to prefer signed to unsigned integer types, and to check for integer overflow. * lib-src/make-docfile.c: Include <stddef.h>, <stdint.h>, <intprops.h>, <min-max.h>. (memory_exhausted): New function. (xmalloc, xrealloc): Use it. (xmalloc, xrealloc, scan_file, struct rcsoc_state, write_c_args) (uncompiled, scan_lisp_file): Prefer signed integer types to unsigned. (xstrdup): Remove. All uses removed. (num_globals, num_globals_allocated, write_globals, scan_c_stream): Use ptrdiff_t, not int, for indexes that in theory could exceed INT_MAX. (add_global): Use const to pacify --enable-gcc-warnings. Make a copy here, rather than relying on strdup calls later. (add_global, write_globals, scan_c_stream): Avoid integer overflow when calculating sizes. (write_globals, scan_c_stream, scan_lisp_file): Avoid memory leak. (scan_c_stream): Check for add_global failure.
This commit is contained in:
parent
02d925e9e5
commit
25ec995c06
1 changed files with 76 additions and 58 deletions
|
@ -37,6 +37,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> /* config.h unconditionally includes this anyway */
|
#include <stdlib.h> /* config.h unconditionally includes this anyway */
|
||||||
|
|
||||||
|
@ -48,6 +50,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
#endif /* WINDOWSNT */
|
#endif /* WINDOWSNT */
|
||||||
|
|
||||||
#include <binary-io.h>
|
#include <binary-io.h>
|
||||||
|
#include <intprops.h>
|
||||||
|
#include <min-max.h>
|
||||||
|
|
||||||
#ifdef DOS_NT
|
#ifdef DOS_NT
|
||||||
/* Defined to be sys_chdir in ms-w32.h, but only #ifdef emacs, so this
|
/* Defined to be sys_chdir in ms-w32.h, but only #ifdef emacs, so this
|
||||||
|
@ -97,36 +101,31 @@ fatal (const char *s1, const char *s2)
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _Noreturn void
|
||||||
|
memory_exhausted (void)
|
||||||
|
{
|
||||||
|
fatal ("virtual memory exhausted", 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Like malloc but get fatal error if memory is exhausted. */
|
/* Like malloc but get fatal error if memory is exhausted. */
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
xmalloc (unsigned int size)
|
xmalloc (ptrdiff_t size)
|
||||||
{
|
{
|
||||||
void *result = (void *) malloc (size);
|
void *result = malloc (size);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
fatal ("virtual memory exhausted", 0);
|
memory_exhausted ();
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Like strdup, but get fatal error if memory is exhausted. */
|
|
||||||
|
|
||||||
static char *
|
|
||||||
xstrdup (char *s)
|
|
||||||
{
|
|
||||||
char *result = strdup (s);
|
|
||||||
if (! result)
|
|
||||||
fatal ("virtual memory exhausted", 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like realloc but get fatal error if memory is exhausted. */
|
/* Like realloc but get fatal error if memory is exhausted. */
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
xrealloc (void *arg, unsigned int size)
|
xrealloc (void *arg, ptrdiff_t size)
|
||||||
{
|
{
|
||||||
void *result = (void *) realloc (arg, size);
|
void *result = realloc (arg, size);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
fatal ("virtual memory exhausted", 0);
|
memory_exhausted ();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +222,7 @@ put_filename (char *filename)
|
||||||
static int
|
static int
|
||||||
scan_file (char *filename)
|
scan_file (char *filename)
|
||||||
{
|
{
|
||||||
|
ptrdiff_t len = strlen (filename);
|
||||||
size_t len = strlen (filename);
|
|
||||||
|
|
||||||
if (!generate_globals)
|
if (!generate_globals)
|
||||||
put_filename (filename);
|
put_filename (filename);
|
||||||
|
@ -250,7 +248,7 @@ static char input_buffer[128];
|
||||||
struct rcsoc_state
|
struct rcsoc_state
|
||||||
{
|
{
|
||||||
/* A count of spaces and newlines that have been read, but not output. */
|
/* A count of spaces and newlines that have been read, but not output. */
|
||||||
unsigned pending_spaces, pending_newlines;
|
intmax_t pending_spaces, pending_newlines;
|
||||||
|
|
||||||
/* Where we're reading from. */
|
/* Where we're reading from. */
|
||||||
FILE *in_file;
|
FILE *in_file;
|
||||||
|
@ -468,10 +466,10 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa
|
||||||
static void
|
static void
|
||||||
write_c_args (char *func, char *buf, int minargs, int maxargs)
|
write_c_args (char *func, char *buf, int minargs, int maxargs)
|
||||||
{
|
{
|
||||||
register char *p;
|
char *p;
|
||||||
int in_ident = 0;
|
int in_ident = 0;
|
||||||
char *ident_start IF_LINT (= NULL);
|
char *ident_start IF_LINT (= NULL);
|
||||||
size_t ident_length = 0;
|
ptrdiff_t ident_length = 0;
|
||||||
|
|
||||||
fputs ("(fn", stdout);
|
fputs ("(fn", stdout);
|
||||||
|
|
||||||
|
@ -575,34 +573,38 @@ enum { DEFUN_noreturn = 1, DEFUN_const = 2 };
|
||||||
|
|
||||||
/* All the variable names we saw while scanning C sources in `-g'
|
/* All the variable names we saw while scanning C sources in `-g'
|
||||||
mode. */
|
mode. */
|
||||||
int num_globals;
|
ptrdiff_t num_globals;
|
||||||
int num_globals_allocated;
|
ptrdiff_t num_globals_allocated;
|
||||||
struct global *globals;
|
struct global *globals;
|
||||||
|
|
||||||
static struct global *
|
static struct global *
|
||||||
add_global (enum global_type type, char *name, int value, char const *svalue)
|
add_global (enum global_type type, char const *name, int value,
|
||||||
|
char const *svalue)
|
||||||
{
|
{
|
||||||
/* Ignore the one non-symbol that can occur. */
|
/* Ignore the one non-symbol that can occur. */
|
||||||
if (strcmp (name, "..."))
|
if (strcmp (name, "..."))
|
||||||
{
|
{
|
||||||
|
if (num_globals == num_globals_allocated)
|
||||||
|
{
|
||||||
|
ptrdiff_t num_globals_max = (min (PTRDIFF_MAX, SIZE_MAX)
|
||||||
|
/ sizeof *globals);
|
||||||
|
if (num_globals_allocated == num_globals_max)
|
||||||
|
memory_exhausted ();
|
||||||
|
if (num_globals_allocated < num_globals_max / 2)
|
||||||
|
num_globals_allocated = 2 * num_globals_allocated + 1;
|
||||||
|
else
|
||||||
|
num_globals_allocated = num_globals_max;
|
||||||
|
globals = xrealloc (globals, num_globals_allocated * sizeof *globals);
|
||||||
|
}
|
||||||
|
|
||||||
++num_globals;
|
++num_globals;
|
||||||
|
|
||||||
if (num_globals_allocated == 0)
|
ptrdiff_t namesize = strlen (name) + 1;
|
||||||
{
|
char *buf = xmalloc (namesize + (svalue ? strlen (svalue) + 1 : 0));
|
||||||
num_globals_allocated = 100;
|
|
||||||
globals = xmalloc (num_globals_allocated * sizeof (struct global));
|
|
||||||
}
|
|
||||||
else if (num_globals == num_globals_allocated)
|
|
||||||
{
|
|
||||||
num_globals_allocated *= 2;
|
|
||||||
globals = xrealloc (globals,
|
|
||||||
num_globals_allocated * sizeof (struct global));
|
|
||||||
}
|
|
||||||
|
|
||||||
globals[num_globals - 1].type = type;
|
globals[num_globals - 1].type = type;
|
||||||
globals[num_globals - 1].name = name;
|
globals[num_globals - 1].name = strcpy (buf, name);
|
||||||
if (svalue)
|
if (svalue)
|
||||||
globals[num_globals - 1].v.svalue = svalue;
|
globals[num_globals - 1].v.svalue = strcpy (buf + namesize, svalue);
|
||||||
else
|
else
|
||||||
globals[num_globals - 1].v.value = value;
|
globals[num_globals - 1].v.value = value;
|
||||||
globals[num_globals - 1].flags = 0;
|
globals[num_globals - 1].flags = 0;
|
||||||
|
@ -649,10 +651,10 @@ close_emacs_globals (int num_symbols)
|
||||||
static void
|
static void
|
||||||
write_globals (void)
|
write_globals (void)
|
||||||
{
|
{
|
||||||
int i, j;
|
ptrdiff_t i, j;
|
||||||
bool seen_defun = false;
|
bool seen_defun = false;
|
||||||
int symnum = 0;
|
ptrdiff_t symnum = 0;
|
||||||
int num_symbols = 0;
|
ptrdiff_t num_symbols = 0;
|
||||||
qsort (globals, num_globals, sizeof (struct global), compare_globals);
|
qsort (globals, num_globals, sizeof (struct global), compare_globals);
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
|
@ -665,6 +667,7 @@ write_globals (void)
|
||||||
&& globals[i].v.value != globals[i + 1].v.value)
|
&& globals[i].v.value != globals[i + 1].v.value)
|
||||||
error ("function '%s' defined twice with differing signatures",
|
error ("function '%s' defined twice with differing signatures",
|
||||||
globals[i].name);
|
globals[i].name);
|
||||||
|
free (globals[i].name);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
num_symbols += globals[i].type == SYMBOL;
|
num_symbols += globals[i].type == SYMBOL;
|
||||||
|
@ -707,7 +710,7 @@ write_globals (void)
|
||||||
globals[i].name, globals[i].name);
|
globals[i].name, globals[i].name);
|
||||||
}
|
}
|
||||||
else if (globals[i].type == SYMBOL)
|
else if (globals[i].type == SYMBOL)
|
||||||
printf (("#define i%s %d\n"
|
printf (("#define i%s %td\n"
|
||||||
"DEFINE_LISP_SYMBOL (%s)\n"),
|
"DEFINE_LISP_SYMBOL (%s)\n"),
|
||||||
globals[i].name, symnum++, globals[i].name);
|
globals[i].name, symnum++, globals[i].name);
|
||||||
else
|
else
|
||||||
|
@ -736,7 +739,7 @@ write_globals (void)
|
||||||
|
|
||||||
puts ("#ifdef DEFINE_SYMBOLS");
|
puts ("#ifdef DEFINE_SYMBOLS");
|
||||||
puts ("static char const *const defsym_name[] = {");
|
puts ("static char const *const defsym_name[] = {");
|
||||||
for (int i = 0; i < num_globals; i++)
|
for (ptrdiff_t i = 0; i < num_globals; i++)
|
||||||
if (globals[i].type == SYMBOL)
|
if (globals[i].type == SYMBOL)
|
||||||
printf ("\t\"%s\",\n", globals[i].v.svalue);
|
printf ("\t\"%s\",\n", globals[i].v.svalue);
|
||||||
puts ("};");
|
puts ("};");
|
||||||
|
@ -745,9 +748,9 @@ write_globals (void)
|
||||||
puts ("#define Qnil builtin_lisp_symbol (0)");
|
puts ("#define Qnil builtin_lisp_symbol (0)");
|
||||||
puts ("#if DEFINE_NON_NIL_Q_SYMBOL_MACROS");
|
puts ("#if DEFINE_NON_NIL_Q_SYMBOL_MACROS");
|
||||||
num_symbols = 0;
|
num_symbols = 0;
|
||||||
for (int i = 0; i < num_globals; i++)
|
for (ptrdiff_t i = 0; i < num_globals; i++)
|
||||||
if (globals[i].type == SYMBOL && num_symbols++ != 0)
|
if (globals[i].type == SYMBOL && num_symbols++ != 0)
|
||||||
printf ("# define %s builtin_lisp_symbol (%d)\n",
|
printf ("# define %s builtin_lisp_symbol (%td)\n",
|
||||||
globals[i].name, num_symbols - 1);
|
globals[i].name, num_symbols - 1);
|
||||||
puts ("#endif");
|
puts ("#endif");
|
||||||
}
|
}
|
||||||
|
@ -820,7 +823,8 @@ scan_c_stream (FILE *infile)
|
||||||
int defvarperbufferflag = 0;
|
int defvarperbufferflag = 0;
|
||||||
int defvarflag = 0;
|
int defvarflag = 0;
|
||||||
enum global_type type = INVALID;
|
enum global_type type = INVALID;
|
||||||
char *name IF_LINT (= 0);
|
static char *name;
|
||||||
|
static ptrdiff_t name_size;
|
||||||
|
|
||||||
if (c != '\n' && c != '\r')
|
if (c != '\n' && c != '\r')
|
||||||
{
|
{
|
||||||
|
@ -925,7 +929,7 @@ scan_c_stream (FILE *infile)
|
||||||
|
|
||||||
if (generate_globals)
|
if (generate_globals)
|
||||||
{
|
{
|
||||||
int i = 0;
|
ptrdiff_t i = 0;
|
||||||
char const *svalue = 0;
|
char const *svalue = 0;
|
||||||
|
|
||||||
/* Skip "," and whitespace. */
|
/* Skip "," and whitespace. */
|
||||||
|
@ -947,7 +951,16 @@ scan_c_stream (FILE *infile)
|
||||||
|| c == '\n' || c == '\r'));
|
|| c == '\n' || c == '\r'));
|
||||||
input_buffer[i] = '\0';
|
input_buffer[i] = '\0';
|
||||||
|
|
||||||
name = xmalloc (i + 1);
|
if (name_size <= i)
|
||||||
|
{
|
||||||
|
free (name);
|
||||||
|
name_size = i + 1;
|
||||||
|
ptrdiff_t doubled;
|
||||||
|
if (! INT_MULTIPLY_WRAPV (name_size, 2, &doubled)
|
||||||
|
&& doubled <= SIZE_MAX)
|
||||||
|
name_size = doubled;
|
||||||
|
name = xmalloc (name_size);
|
||||||
|
}
|
||||||
memcpy (name, input_buffer, i + 1);
|
memcpy (name, input_buffer, i + 1);
|
||||||
|
|
||||||
if (type == SYMBOL)
|
if (type == SYMBOL)
|
||||||
|
@ -958,7 +971,7 @@ scan_c_stream (FILE *infile)
|
||||||
if (c != '"')
|
if (c != '"')
|
||||||
continue;
|
continue;
|
||||||
c = read_c_string_or_comment (infile, -1, 0, 0);
|
c = read_c_string_or_comment (infile, -1, 0, 0);
|
||||||
svalue = xstrdup (input_buffer);
|
svalue = input_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defunflag)
|
if (!defunflag)
|
||||||
|
@ -1024,6 +1037,8 @@ scan_c_stream (FILE *infile)
|
||||||
if (generate_globals)
|
if (generate_globals)
|
||||||
{
|
{
|
||||||
struct global *g = add_global (FUNCTION, name, maxargs, 0);
|
struct global *g = add_global (FUNCTION, name, maxargs, 0);
|
||||||
|
if (!g)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* The following code tries to recognize function attributes
|
/* The following code tries to recognize function attributes
|
||||||
specified after the docstring, e.g.:
|
specified after the docstring, e.g.:
|
||||||
|
@ -1278,7 +1293,7 @@ static int
|
||||||
scan_lisp_file (const char *filename, const char *mode)
|
scan_lisp_file (const char *filename, const char *mode)
|
||||||
{
|
{
|
||||||
FILE *infile;
|
FILE *infile;
|
||||||
register int c;
|
int c;
|
||||||
char *saved_string = 0;
|
char *saved_string = 0;
|
||||||
/* These are the only files that are loaded uncompiled, and must
|
/* These are the only files that are loaded uncompiled, and must
|
||||||
follow the conventions of the doc strings expected by this
|
follow the conventions of the doc strings expected by this
|
||||||
|
@ -1286,7 +1301,7 @@ scan_lisp_file (const char *filename, const char *mode)
|
||||||
byte compiler when it produces the .elc files. */
|
byte compiler when it produces the .elc files. */
|
||||||
static struct {
|
static struct {
|
||||||
const char *fn;
|
const char *fn;
|
||||||
size_t fl;
|
int fl;
|
||||||
} const uncompiled[] = {
|
} const uncompiled[] = {
|
||||||
DEF_ELISP_FILE (loaddefs.el),
|
DEF_ELISP_FILE (loaddefs.el),
|
||||||
DEF_ELISP_FILE (loadup.el),
|
DEF_ELISP_FILE (loadup.el),
|
||||||
|
@ -1295,7 +1310,7 @@ scan_lisp_file (const char *filename, const char *mode)
|
||||||
DEF_ELISP_FILE (eucjp-ms.el)
|
DEF_ELISP_FILE (eucjp-ms.el)
|
||||||
};
|
};
|
||||||
int i, match;
|
int i, match;
|
||||||
size_t flen = strlen (filename);
|
int flen = strlen (filename);
|
||||||
|
|
||||||
if (generate_globals)
|
if (generate_globals)
|
||||||
fatal ("scanning lisp file when -g specified", 0);
|
fatal ("scanning lisp file when -g specified", 0);
|
||||||
|
@ -1345,15 +1360,17 @@ scan_lisp_file (const char *filename, const char *mode)
|
||||||
c = getc (infile);
|
c = getc (infile);
|
||||||
if (c == '@')
|
if (c == '@')
|
||||||
{
|
{
|
||||||
size_t length = 0;
|
ptrdiff_t length = 0;
|
||||||
size_t i;
|
ptrdiff_t i;
|
||||||
|
|
||||||
/* Read the length. */
|
/* Read the length. */
|
||||||
while ((c = getc (infile),
|
while ((c = getc (infile),
|
||||||
c >= '0' && c <= '9'))
|
c >= '0' && c <= '9'))
|
||||||
{
|
{
|
||||||
length *= 10;
|
if (INT_MULTIPLY_WRAPV (length, 10, &length)
|
||||||
length += c - '0';
|
|| INT_ADD_WRAPV (length, c - '0', &length)
|
||||||
|
|| SIZE_MAX < length)
|
||||||
|
memory_exhausted ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length <= 1)
|
if (length <= 1)
|
||||||
|
@ -1369,7 +1386,7 @@ scan_lisp_file (const char *filename, const char *mode)
|
||||||
|
|
||||||
/* Read in the contents. */
|
/* Read in the contents. */
|
||||||
free (saved_string);
|
free (saved_string);
|
||||||
saved_string = (char *) xmalloc (length);
|
saved_string = xmalloc (length);
|
||||||
for (i = 0; i < length; i++)
|
for (i = 0; i < length; i++)
|
||||||
saved_string[i] = getc (infile);
|
saved_string[i] = getc (infile);
|
||||||
/* The last character is a ^_.
|
/* The last character is a ^_.
|
||||||
|
@ -1606,6 +1623,7 @@ scan_lisp_file (const char *filename, const char *mode)
|
||||||
else
|
else
|
||||||
read_c_string_or_comment (infile, 1, 0, 0);
|
read_c_string_or_comment (infile, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
free (saved_string);
|
||||||
fclose (infile);
|
fclose (infile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue