diff options
| author | Paul Eggert | 2016-02-10 10:14:50 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-02-10 11:41:10 -0800 |
| commit | 25ec995c064d4e658fe3f9af084f120ae21a021a (patch) | |
| tree | 796426490202643af30b6108c8968d311e22f7a9 /lib-src | |
| parent | 02d925e9e55089fabfe03e5a911c391b9322978f (diff) | |
| download | emacs-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.c | 132 |
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. */ | 104 | static _Noreturn void |
| 101 | 105 | memory_exhausted (void) | |
| 102 | static void * | ||
| 103 | xmalloc (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 | ||
| 113 | static char * | 112 | static void * |
| 114 | xstrdup (char *s) | 113 | xmalloc (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 | ||
| 124 | static void * | 123 | static void * |
| 125 | xrealloc (void *arg, unsigned int size) | 124 | xrealloc (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) | |||
| 223 | static int | 222 | static int |
| 224 | scan_file (char *filename) | 223 | scan_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]; | |||
| 250 | struct rcsoc_state | 248 | struct 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 | |||
| 468 | static void | 466 | static void |
| 469 | write_c_args (char *func, char *buf, int minargs, int maxargs) | 467 | write_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. */ |
| 578 | int num_globals; | 576 | ptrdiff_t num_globals; |
| 579 | int num_globals_allocated; | 577 | ptrdiff_t num_globals_allocated; |
| 580 | struct global *globals; | 578 | struct global *globals; |
| 581 | 579 | ||
| 582 | static struct global * | 580 | static struct global * |
| 583 | add_global (enum global_type type, char *name, int value, char const *svalue) | 581 | add_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) | |||
| 649 | static void | 651 | static void |
| 650 | write_globals (void) | 652 | write_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 | |||
| 1278 | scan_lisp_file (const char *filename, const char *mode) | 1293 | scan_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 | } |