aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src
diff options
context:
space:
mode:
authorPaul Eggert2016-02-10 10:14:50 -0800
committerPaul Eggert2016-02-10 11:41:10 -0800
commit25ec995c064d4e658fe3f9af084f120ae21a021a (patch)
tree796426490202643af30b6108c8968d311e22f7a9 /lib-src
parent02d925e9e55089fabfe03e5a911c391b9322978f (diff)
downloademacs-25ec995c064d4e658fe3f9af084f120ae21a021a.tar.gz
emacs-25ec995c064d4e658fe3f9af084f120ae21a021a.zip
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.
Diffstat (limited to 'lib-src')
-rw-r--r--lib-src/make-docfile.c132
1 files changed, 75 insertions, 57 deletions
diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index 02b5e766ee2..4ab3729bad0 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -37,6 +37,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
37#include <config.h> 37#include <config.h>
38 38
39#include <stdbool.h> 39#include <stdbool.h>
40#include <stddef.h>
41#include <stdint.h>
40#include <stdio.h> 42#include <stdio.h>
41#include <stdlib.h> /* config.h unconditionally includes this anyway */ 43#include <stdlib.h> /* config.h unconditionally includes this anyway */
42 44
@@ -48,6 +50,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
48#endif /* WINDOWSNT */ 50#endif /* WINDOWSNT */
49 51
50#include <binary-io.h> 52#include <binary-io.h>
53#include <intprops.h>
54#include <min-max.h>
51 55
52#ifdef DOS_NT 56#ifdef DOS_NT
53/* Defined to be sys_chdir in ms-w32.h, but only #ifdef emacs, so this 57/* 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)
97 exit (EXIT_FAILURE); 101 exit (EXIT_FAILURE);
98} 102}
99 103
100/* Like malloc but get fatal error if memory is exhausted. */ 104static _Noreturn void
101 105memory_exhausted (void)
102static void *
103xmalloc (unsigned int size)
104{ 106{
105 void *result = (void *) malloc (size); 107 fatal ("virtual memory exhausted", 0);
106 if (result == NULL)
107 fatal ("virtual memory exhausted", 0);
108 return result;
109} 108}
110 109
111/* Like strdup, but get fatal error if memory is exhausted. */ 110/* Like malloc but get fatal error if memory is exhausted. */
112 111
113static char * 112static void *
114xstrdup (char *s) 113xmalloc (ptrdiff_t size)
115{ 114{
116 char *result = strdup (s); 115 void *result = malloc (size);
117 if (! result) 116 if (result == NULL)
118 fatal ("virtual memory exhausted", 0); 117 memory_exhausted ();
119 return result; 118 return result;
120} 119}
121 120
122/* Like realloc but get fatal error if memory is exhausted. */ 121/* Like realloc but get fatal error if memory is exhausted. */
123 122
124static void * 123static void *
125xrealloc (void *arg, unsigned int size) 124xrealloc (void *arg, ptrdiff_t size)
126{ 125{
127 void *result = (void *) realloc (arg, size); 126 void *result = realloc (arg, size);
128 if (result == NULL) 127 if (result == NULL)
129 fatal ("virtual memory exhausted", 0); 128 memory_exhausted ();
130 return result; 129 return result;
131} 130}
132 131
@@ -223,8 +222,7 @@ put_filename (char *filename)
223static int 222static int
224scan_file (char *filename) 223scan_file (char *filename)
225{ 224{
226 225 ptrdiff_t len = strlen (filename);
227 size_t len = strlen (filename);
228 226
229 if (!generate_globals) 227 if (!generate_globals)
230 put_filename (filename); 228 put_filename (filename);
@@ -250,7 +248,7 @@ static char input_buffer[128];
250struct rcsoc_state 248struct rcsoc_state
251{ 249{
252 /* A count of spaces and newlines that have been read, but not output. */ 250 /* A count of spaces and newlines that have been read, but not output. */
253 unsigned pending_spaces, pending_newlines; 251 intmax_t pending_spaces, pending_newlines;
254 252
255 /* Where we're reading from. */ 253 /* Where we're reading from. */
256 FILE *in_file; 254 FILE *in_file;
@@ -468,10 +466,10 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa
468static void 466static void
469write_c_args (char *func, char *buf, int minargs, int maxargs) 467write_c_args (char *func, char *buf, int minargs, int maxargs)
470{ 468{
471 register char *p; 469 char *p;
472 int in_ident = 0; 470 int in_ident = 0;
473 char *ident_start IF_LINT (= NULL); 471 char *ident_start IF_LINT (= NULL);
474 size_t ident_length = 0; 472 ptrdiff_t ident_length = 0;
475 473
476 fputs ("(fn", stdout); 474 fputs ("(fn", stdout);
477 475
@@ -575,34 +573,38 @@ enum { DEFUN_noreturn = 1, DEFUN_const = 2 };
575 573
576/* All the variable names we saw while scanning C sources in `-g' 574/* All the variable names we saw while scanning C sources in `-g'
577 mode. */ 575 mode. */
578int num_globals; 576ptrdiff_t num_globals;
579int num_globals_allocated; 577ptrdiff_t num_globals_allocated;
580struct global *globals; 578struct global *globals;
581 579
582static struct global * 580static struct global *
583add_global (enum global_type type, char *name, int value, char const *svalue) 581add_global (enum global_type type, char const *name, int value,
582 char const *svalue)
584{ 583{
585 /* Ignore the one non-symbol that can occur. */ 584 /* Ignore the one non-symbol that can occur. */
586 if (strcmp (name, "...")) 585 if (strcmp (name, "..."))
587 { 586 {
588 ++num_globals; 587 if (num_globals == num_globals_allocated)
589
590 if (num_globals_allocated == 0)
591 {
592 num_globals_allocated = 100;
593 globals = xmalloc (num_globals_allocated * sizeof (struct global));
594 }
595 else if (num_globals == num_globals_allocated)
596 { 588 {
597 num_globals_allocated *= 2; 589 ptrdiff_t num_globals_max = (min (PTRDIFF_MAX, SIZE_MAX)
598 globals = xrealloc (globals, 590 / sizeof *globals);
599 num_globals_allocated * sizeof (struct global)); 591 if (num_globals_allocated == num_globals_max)
592 memory_exhausted ();
593 if (num_globals_allocated < num_globals_max / 2)
594 num_globals_allocated = 2 * num_globals_allocated + 1;
595 else
596 num_globals_allocated = num_globals_max;
597 globals = xrealloc (globals, num_globals_allocated * sizeof *globals);
600 } 598 }
601 599
600 ++num_globals;
601
602 ptrdiff_t namesize = strlen (name) + 1;
603 char *buf = xmalloc (namesize + (svalue ? strlen (svalue) + 1 : 0));
602 globals[num_globals - 1].type = type; 604 globals[num_globals - 1].type = type;
603 globals[num_globals - 1].name = name; 605 globals[num_globals - 1].name = strcpy (buf, name);
604 if (svalue) 606 if (svalue)
605 globals[num_globals - 1].v.svalue = svalue; 607 globals[num_globals - 1].v.svalue = strcpy (buf + namesize, svalue);
606 else 608 else
607 globals[num_globals - 1].v.value = value; 609 globals[num_globals - 1].v.value = value;
608 globals[num_globals - 1].flags = 0; 610 globals[num_globals - 1].flags = 0;
@@ -649,10 +651,10 @@ close_emacs_globals (int num_symbols)
649static void 651static void
650write_globals (void) 652write_globals (void)
651{ 653{
652 int i, j; 654 ptrdiff_t i, j;
653 bool seen_defun = false; 655 bool seen_defun = false;
654 int symnum = 0; 656 ptrdiff_t symnum = 0;
655 int num_symbols = 0; 657 ptrdiff_t num_symbols = 0;
656 qsort (globals, num_globals, sizeof (struct global), compare_globals); 658 qsort (globals, num_globals, sizeof (struct global), compare_globals);
657 659
658 j = 0; 660 j = 0;
@@ -665,6 +667,7 @@ write_globals (void)
665 && globals[i].v.value != globals[i + 1].v.value) 667 && globals[i].v.value != globals[i + 1].v.value)
666 error ("function '%s' defined twice with differing signatures", 668 error ("function '%s' defined twice with differing signatures",
667 globals[i].name); 669 globals[i].name);
670 free (globals[i].name);
668 i++; 671 i++;
669 } 672 }
670 num_symbols += globals[i].type == SYMBOL; 673 num_symbols += globals[i].type == SYMBOL;
@@ -707,7 +710,7 @@ write_globals (void)
707 globals[i].name, globals[i].name); 710 globals[i].name, globals[i].name);
708 } 711 }
709 else if (globals[i].type == SYMBOL) 712 else if (globals[i].type == SYMBOL)
710 printf (("#define i%s %d\n" 713 printf (("#define i%s %td\n"
711 "DEFINE_LISP_SYMBOL (%s)\n"), 714 "DEFINE_LISP_SYMBOL (%s)\n"),
712 globals[i].name, symnum++, globals[i].name); 715 globals[i].name, symnum++, globals[i].name);
713 else 716 else
@@ -736,7 +739,7 @@ write_globals (void)
736 739
737 puts ("#ifdef DEFINE_SYMBOLS"); 740 puts ("#ifdef DEFINE_SYMBOLS");
738 puts ("static char const *const defsym_name[] = {"); 741 puts ("static char const *const defsym_name[] = {");
739 for (int i = 0; i < num_globals; i++) 742 for (ptrdiff_t i = 0; i < num_globals; i++)
740 if (globals[i].type == SYMBOL) 743 if (globals[i].type == SYMBOL)
741 printf ("\t\"%s\",\n", globals[i].v.svalue); 744 printf ("\t\"%s\",\n", globals[i].v.svalue);
742 puts ("};"); 745 puts ("};");
@@ -745,9 +748,9 @@ write_globals (void)
745 puts ("#define Qnil builtin_lisp_symbol (0)"); 748 puts ("#define Qnil builtin_lisp_symbol (0)");
746 puts ("#if DEFINE_NON_NIL_Q_SYMBOL_MACROS"); 749 puts ("#if DEFINE_NON_NIL_Q_SYMBOL_MACROS");
747 num_symbols = 0; 750 num_symbols = 0;
748 for (int i = 0; i < num_globals; i++) 751 for (ptrdiff_t i = 0; i < num_globals; i++)
749 if (globals[i].type == SYMBOL && num_symbols++ != 0) 752 if (globals[i].type == SYMBOL && num_symbols++ != 0)
750 printf ("# define %s builtin_lisp_symbol (%d)\n", 753 printf ("# define %s builtin_lisp_symbol (%td)\n",
751 globals[i].name, num_symbols - 1); 754 globals[i].name, num_symbols - 1);
752 puts ("#endif"); 755 puts ("#endif");
753} 756}
@@ -820,7 +823,8 @@ scan_c_stream (FILE *infile)
820 int defvarperbufferflag = 0; 823 int defvarperbufferflag = 0;
821 int defvarflag = 0; 824 int defvarflag = 0;
822 enum global_type type = INVALID; 825 enum global_type type = INVALID;
823 char *name IF_LINT (= 0); 826 static char *name;
827 static ptrdiff_t name_size;
824 828
825 if (c != '\n' && c != '\r') 829 if (c != '\n' && c != '\r')
826 { 830 {
@@ -925,7 +929,7 @@ scan_c_stream (FILE *infile)
925 929
926 if (generate_globals) 930 if (generate_globals)
927 { 931 {
928 int i = 0; 932 ptrdiff_t i = 0;
929 char const *svalue = 0; 933 char const *svalue = 0;
930 934
931 /* Skip "," and whitespace. */ 935 /* Skip "," and whitespace. */
@@ -947,7 +951,16 @@ scan_c_stream (FILE *infile)
947 || c == '\n' || c == '\r')); 951 || c == '\n' || c == '\r'));
948 input_buffer[i] = '\0'; 952 input_buffer[i] = '\0';
949 953
950 name = xmalloc (i + 1); 954 if (name_size <= i)
955 {
956 free (name);
957 name_size = i + 1;
958 ptrdiff_t doubled;
959 if (! INT_MULTIPLY_WRAPV (name_size, 2, &doubled)
960 && doubled <= SIZE_MAX)
961 name_size = doubled;
962 name = xmalloc (name_size);
963 }
951 memcpy (name, input_buffer, i + 1); 964 memcpy (name, input_buffer, i + 1);
952 965
953 if (type == SYMBOL) 966 if (type == SYMBOL)
@@ -958,7 +971,7 @@ scan_c_stream (FILE *infile)
958 if (c != '"') 971 if (c != '"')
959 continue; 972 continue;
960 c = read_c_string_or_comment (infile, -1, 0, 0); 973 c = read_c_string_or_comment (infile, -1, 0, 0);
961 svalue = xstrdup (input_buffer); 974 svalue = input_buffer;
962 } 975 }
963 976
964 if (!defunflag) 977 if (!defunflag)
@@ -1024,6 +1037,8 @@ scan_c_stream (FILE *infile)
1024 if (generate_globals) 1037 if (generate_globals)
1025 { 1038 {
1026 struct global *g = add_global (FUNCTION, name, maxargs, 0); 1039 struct global *g = add_global (FUNCTION, name, maxargs, 0);
1040 if (!g)
1041 continue;
1027 1042
1028 /* The following code tries to recognize function attributes 1043 /* The following code tries to recognize function attributes
1029 specified after the docstring, e.g.: 1044 specified after the docstring, e.g.:
@@ -1278,7 +1293,7 @@ static int
1278scan_lisp_file (const char *filename, const char *mode) 1293scan_lisp_file (const char *filename, const char *mode)
1279{ 1294{
1280 FILE *infile; 1295 FILE *infile;
1281 register int c; 1296 int c;
1282 char *saved_string = 0; 1297 char *saved_string = 0;
1283 /* These are the only files that are loaded uncompiled, and must 1298 /* These are the only files that are loaded uncompiled, and must
1284 follow the conventions of the doc strings expected by this 1299 follow the conventions of the doc strings expected by this
@@ -1286,7 +1301,7 @@ scan_lisp_file (const char *filename, const char *mode)
1286 byte compiler when it produces the .elc files. */ 1301 byte compiler when it produces the .elc files. */
1287 static struct { 1302 static struct {
1288 const char *fn; 1303 const char *fn;
1289 size_t fl; 1304 int fl;
1290 } const uncompiled[] = { 1305 } const uncompiled[] = {
1291 DEF_ELISP_FILE (loaddefs.el), 1306 DEF_ELISP_FILE (loaddefs.el),
1292 DEF_ELISP_FILE (loadup.el), 1307 DEF_ELISP_FILE (loadup.el),
@@ -1295,7 +1310,7 @@ scan_lisp_file (const char *filename, const char *mode)
1295 DEF_ELISP_FILE (eucjp-ms.el) 1310 DEF_ELISP_FILE (eucjp-ms.el)
1296 }; 1311 };
1297 int i, match; 1312 int i, match;
1298 size_t flen = strlen (filename); 1313 int flen = strlen (filename);
1299 1314
1300 if (generate_globals) 1315 if (generate_globals)
1301 fatal ("scanning lisp file when -g specified", 0); 1316 fatal ("scanning lisp file when -g specified", 0);
@@ -1345,15 +1360,17 @@ scan_lisp_file (const char *filename, const char *mode)
1345 c = getc (infile); 1360 c = getc (infile);
1346 if (c == '@') 1361 if (c == '@')
1347 { 1362 {
1348 size_t length = 0; 1363 ptrdiff_t length = 0;
1349 size_t i; 1364 ptrdiff_t i;
1350 1365
1351 /* Read the length. */ 1366 /* Read the length. */
1352 while ((c = getc (infile), 1367 while ((c = getc (infile),
1353 c >= '0' && c <= '9')) 1368 c >= '0' && c <= '9'))
1354 { 1369 {
1355 length *= 10; 1370 if (INT_MULTIPLY_WRAPV (length, 10, &length)
1356 length += c - '0'; 1371 || INT_ADD_WRAPV (length, c - '0', &length)
1372 || SIZE_MAX < length)
1373 memory_exhausted ();
1357 } 1374 }
1358 1375
1359 if (length <= 1) 1376 if (length <= 1)
@@ -1369,7 +1386,7 @@ scan_lisp_file (const char *filename, const char *mode)
1369 1386
1370 /* Read in the contents. */ 1387 /* Read in the contents. */
1371 free (saved_string); 1388 free (saved_string);
1372 saved_string = (char *) xmalloc (length); 1389 saved_string = xmalloc (length);
1373 for (i = 0; i < length; i++) 1390 for (i = 0; i < length; i++)
1374 saved_string[i] = getc (infile); 1391 saved_string[i] = getc (infile);
1375 /* The last character is a ^_. 1392 /* The last character is a ^_.
@@ -1606,6 +1623,7 @@ scan_lisp_file (const char *filename, const char *mode)
1606 else 1623 else
1607 read_c_string_or_comment (infile, 1, 0, 0); 1624 read_c_string_or_comment (infile, 1, 0, 0);
1608 } 1625 }
1626 free (saved_string);
1609 fclose (infile); 1627 fclose (infile);
1610 return 0; 1628 return 0;
1611} 1629}