diff options
| author | Paul Eggert | 2013-07-17 19:12:59 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-07-17 19:12:59 -0700 |
| commit | f4b1eb36186a2f873d84d4c089292f9fb0394d31 (patch) | |
| tree | ea6a4d904679b9f50026abb6dfab00f9b693eb6a /src | |
| parent | a0931322f6c257bb4a4a678f62dcb4ae3b253221 (diff) | |
| download | emacs-f4b1eb36186a2f873d84d4c089292f9fb0394d31.tar.gz emacs-f4b1eb36186a2f873d84d4c089292f9fb0394d31.zip | |
* charset.c: Fix file descriptor leaks and errno issues.
Include <errno.h>.
(load_charset_map_from_file): Don't leak file descriptor on error.
Use plain record_xmalloc since the allocation is larger than
MAX_ALLOCA; that's simpler here. Simplify test for exhaustion
of entries.
* eval.c (record_unwind_protect_nothing):
* fileio.c (fclose_unwind):
New functions.
* lread.c (load_unwind): Remove. All uses replaced by fclose_unwind.
The replacement doesn't block input, but that no longer seems
necessary.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 15 | ||||
| -rw-r--r-- | src/charset.c | 30 | ||||
| -rw-r--r-- | src/eval.c | 21 | ||||
| -rw-r--r-- | src/fileio.c | 7 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/lread.c | 15 |
6 files changed, 65 insertions, 25 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 189a353bde6..3f667a7bcc7 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | 2013-07-18 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | * charset.c: Fix file descriptor leaks and errno issues. | ||
| 4 | Include <errno.h>. | ||
| 5 | (load_charset_map_from_file): Don't leak file descriptor on error. | ||
| 6 | Use plain record_xmalloc since the allocation is larger than | ||
| 7 | MAX_ALLOCA; that's simpler here. Simplify test for exhaustion | ||
| 8 | of entries. | ||
| 9 | * eval.c (record_unwind_protect_nothing): | ||
| 10 | * fileio.c (fclose_unwind): | ||
| 11 | New functions. | ||
| 12 | * lread.c (load_unwind): Remove. All uses replaced by fclose_unwind. | ||
| 13 | The replacement doesn't block input, but that no longer seems | ||
| 14 | necessary. | ||
| 15 | |||
| 1 | 2013-07-17 Paul Eggert <eggert@cs.ucla.edu> | 16 | 2013-07-17 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 17 | ||
| 3 | * lread.c: Fix file descriptor leaks and errno issues. | 18 | * lread.c: Fix file descriptor leaks and errno issues. |
diff --git a/src/charset.c b/src/charset.c index 6b7e81c156d..eedf65faa6c 100644 --- a/src/charset.c +++ b/src/charset.c | |||
| @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 28 | 28 | ||
| 29 | #define CHARSET_INLINE EXTERN_INLINE | 29 | #define CHARSET_INLINE EXTERN_INLINE |
| 30 | 30 | ||
| 31 | #include <errno.h> | ||
| 31 | #include <stdio.h> | 32 | #include <stdio.h> |
| 32 | #include <unistd.h> | 33 | #include <unistd.h> |
| 33 | #include <limits.h> | 34 | #include <limits.h> |
| @@ -477,7 +478,8 @@ read_hex (FILE *fp, bool *eof, bool *overflow) | |||
| 477 | `file-name-handler-alist' to avoid running any Lisp code. */ | 478 | `file-name-handler-alist' to avoid running any Lisp code. */ |
| 478 | 479 | ||
| 479 | static void | 480 | static void |
| 480 | load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int control_flag) | 481 | load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, |
| 482 | int control_flag) | ||
| 481 | { | 483 | { |
| 482 | unsigned min_code = CHARSET_MIN_CODE (charset); | 484 | unsigned min_code = CHARSET_MIN_CODE (charset); |
| 483 | unsigned max_code = CHARSET_MAX_CODE (charset); | 485 | unsigned max_code = CHARSET_MAX_CODE (charset); |
| @@ -487,21 +489,26 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co | |||
| 487 | struct charset_map_entries *head, *entries; | 489 | struct charset_map_entries *head, *entries; |
| 488 | int n_entries; | 490 | int n_entries; |
| 489 | ptrdiff_t count; | 491 | ptrdiff_t count; |
| 490 | USE_SAFE_ALLOCA; | ||
| 491 | 492 | ||
| 492 | suffixes = list2 (build_string (".map"), build_string (".TXT")); | 493 | suffixes = list2 (build_string (".map"), build_string (".TXT")); |
| 493 | 494 | ||
| 494 | count = SPECPDL_INDEX (); | 495 | count = SPECPDL_INDEX (); |
| 496 | record_unwind_protect_nothing (); | ||
| 495 | specbind (Qfile_name_handler_alist, Qnil); | 497 | specbind (Qfile_name_handler_alist, Qnil); |
| 496 | fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil); | 498 | fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil); |
| 497 | unbind_to (count, Qnil); | 499 | fp = fd < 0 ? 0 : fdopen (fd, "r"); |
| 498 | if (fd < 0 | 500 | if (!fp) |
| 499 | || ! (fp = fdopen (fd, "r"))) | 501 | { |
| 500 | error ("Failure in loading charset map: %s", SDATA (mapfile)); | 502 | int open_errno = errno; |
| 503 | emacs_close (fd); | ||
| 504 | report_file_errno ("Loading charset map", mapfile, open_errno); | ||
| 505 | } | ||
| 506 | set_unwind_protect_ptr (count, fclose_unwind, fp); | ||
| 507 | unbind_to (count + 1, Qnil); | ||
| 501 | 508 | ||
| 502 | /* Use SAFE_ALLOCA instead of alloca, as `charset_map_entries' is | 509 | /* Use record_xmalloc, as `charset_map_entries' is |
| 503 | large (larger than MAX_ALLOCA). */ | 510 | large (larger than MAX_ALLOCA). */ |
| 504 | head = SAFE_ALLOCA (sizeof *head); | 511 | head = record_xmalloc (sizeof *head); |
| 505 | entries = head; | 512 | entries = head; |
| 506 | memset (entries, 0, sizeof (struct charset_map_entries)); | 513 | memset (entries, 0, sizeof (struct charset_map_entries)); |
| 507 | 514 | ||
| @@ -530,9 +537,9 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co | |||
| 530 | if (from < min_code || to > max_code || from > to || c > MAX_CHAR) | 537 | if (from < min_code || to > max_code || from > to || c > MAX_CHAR) |
| 531 | continue; | 538 | continue; |
| 532 | 539 | ||
| 533 | if (n_entries > 0 && (n_entries % 0x10000) == 0) | 540 | if (n_entries == 0x10000) |
| 534 | { | 541 | { |
| 535 | entries->next = SAFE_ALLOCA (sizeof *entries->next); | 542 | entries->next = record_xmalloc (sizeof *entries->next); |
| 536 | entries = entries->next; | 543 | entries = entries->next; |
| 537 | memset (entries, 0, sizeof (struct charset_map_entries)); | 544 | memset (entries, 0, sizeof (struct charset_map_entries)); |
| 538 | n_entries = 0; | 545 | n_entries = 0; |
| @@ -544,9 +551,10 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co | |||
| 544 | n_entries++; | 551 | n_entries++; |
| 545 | } | 552 | } |
| 546 | fclose (fp); | 553 | fclose (fp); |
| 554 | clear_unwind_protect (count); | ||
| 547 | 555 | ||
| 548 | load_charset_map (charset, head, n_entries, control_flag); | 556 | load_charset_map (charset, head, n_entries, control_flag); |
| 549 | SAFE_FREE (); | 557 | unbind_to (count, Qnil); |
| 550 | } | 558 | } |
| 551 | 559 | ||
| 552 | static void | 560 | static void |
diff --git a/src/eval.c b/src/eval.c index a4f94ee1415..23834cb54f6 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -3190,6 +3190,8 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3190 | } | 3190 | } |
| 3191 | } | 3191 | } |
| 3192 | 3192 | ||
| 3193 | /* Push unwind-protect entries of various types. */ | ||
| 3194 | |||
| 3193 | void | 3195 | void |
| 3194 | record_unwind_protect (void (*function) (Lisp_Object), Lisp_Object arg) | 3196 | record_unwind_protect (void (*function) (Lisp_Object), Lisp_Object arg) |
| 3195 | { | 3197 | { |
| @@ -3229,6 +3231,18 @@ static void | |||
| 3229 | do_nothing (void) | 3231 | do_nothing (void) |
| 3230 | {} | 3232 | {} |
| 3231 | 3233 | ||
| 3234 | /* Push an unwind-protect entry that does nothing, so that | ||
| 3235 | set_unwind_protect_ptr can overwrite it later. */ | ||
| 3236 | |||
| 3237 | void | ||
| 3238 | record_unwind_protect_nothing (void) | ||
| 3239 | { | ||
| 3240 | record_unwind_protect_void (do_nothing); | ||
| 3241 | } | ||
| 3242 | |||
| 3243 | /* Clear the unwind-protect entry COUNT, so that it does nothing. | ||
| 3244 | It need not be at the top of the stack. */ | ||
| 3245 | |||
| 3232 | void | 3246 | void |
| 3233 | clear_unwind_protect (ptrdiff_t count) | 3247 | clear_unwind_protect (ptrdiff_t count) |
| 3234 | { | 3248 | { |
| @@ -3237,6 +3251,10 @@ clear_unwind_protect (ptrdiff_t count) | |||
| 3237 | p->unwind_void.func = do_nothing; | 3251 | p->unwind_void.func = do_nothing; |
| 3238 | } | 3252 | } |
| 3239 | 3253 | ||
| 3254 | /* Set the unwind-protect entry COUNT so that it invokes FUNC (ARG). | ||
| 3255 | It need not be at the top of the stack. Discard the entry's | ||
| 3256 | previous value without invoking it. */ | ||
| 3257 | |||
| 3240 | void | 3258 | void |
| 3241 | set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg) | 3259 | set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg) |
| 3242 | { | 3260 | { |
| @@ -3246,6 +3264,9 @@ set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg) | |||
| 3246 | p->unwind_ptr.arg = arg; | 3264 | p->unwind_ptr.arg = arg; |
| 3247 | } | 3265 | } |
| 3248 | 3266 | ||
| 3267 | /* Pop and execute entries from the unwind-protect stack until the | ||
| 3268 | depth COUNT is reached. Return VALUE. */ | ||
| 3269 | |||
| 3249 | Lisp_Object | 3270 | Lisp_Object |
| 3250 | unbind_to (ptrdiff_t count, Lisp_Object value) | 3271 | unbind_to (ptrdiff_t count, Lisp_Object value) |
| 3251 | { | 3272 | { |
diff --git a/src/fileio.c b/src/fileio.c index 28b2dc84726..5fe359d58bb 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -220,6 +220,13 @@ close_file_unwind (int fd) | |||
| 220 | emacs_close (fd); | 220 | emacs_close (fd); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void | ||
| 224 | fclose_unwind (void *arg) | ||
| 225 | { | ||
| 226 | FILE *stream = arg; | ||
| 227 | fclose (stream); | ||
| 228 | } | ||
| 229 | |||
| 223 | /* Restore point, having saved it as a marker. */ | 230 | /* Restore point, having saved it as a marker. */ |
| 224 | 231 | ||
| 225 | void | 232 | void |
diff --git a/src/lisp.h b/src/lisp.h index 231dbee2d21..518de9db0ff 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3743,6 +3743,7 @@ extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object); | |||
| 3743 | extern void record_unwind_protect_int (void (*) (int), int); | 3743 | extern void record_unwind_protect_int (void (*) (int), int); |
| 3744 | extern void record_unwind_protect_ptr (void (*) (void *), void *); | 3744 | extern void record_unwind_protect_ptr (void (*) (void *), void *); |
| 3745 | extern void record_unwind_protect_void (void (*) (void)); | 3745 | extern void record_unwind_protect_void (void (*) (void)); |
| 3746 | extern void record_unwind_protect_nothing (void); | ||
| 3746 | extern void clear_unwind_protect (ptrdiff_t); | 3747 | extern void clear_unwind_protect (ptrdiff_t); |
| 3747 | extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *); | 3748 | extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *); |
| 3748 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); | 3749 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); |
| @@ -3827,6 +3828,7 @@ extern Lisp_Object Qfile_name_history; | |||
| 3827 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object, Lisp_Object); | 3828 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object, Lisp_Object); |
| 3828 | EXFUN (Fread_file_name, 6); /* Not a normal DEFUN. */ | 3829 | EXFUN (Fread_file_name, 6); /* Not a normal DEFUN. */ |
| 3829 | extern void close_file_unwind (int); | 3830 | extern void close_file_unwind (int); |
| 3831 | extern void fclose_unwind (void *); | ||
| 3830 | extern void restore_point_unwind (Lisp_Object); | 3832 | extern void restore_point_unwind (Lisp_Object); |
| 3831 | extern _Noreturn void report_file_errno (const char *, Lisp_Object, int); | 3833 | extern _Noreturn void report_file_errno (const char *, Lisp_Object, int); |
| 3832 | extern _Noreturn void report_file_error (const char *, Lisp_Object); | 3834 | extern _Noreturn void report_file_error (const char *, Lisp_Object); |
diff --git a/src/lread.c b/src/lread.c index ee387b832c5..146543a99fd 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -145,7 +145,6 @@ static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), | |||
| 145 | static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool, | 145 | static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool, |
| 146 | Lisp_Object, Lisp_Object, | 146 | Lisp_Object, Lisp_Object, |
| 147 | Lisp_Object, Lisp_Object); | 147 | Lisp_Object, Lisp_Object); |
| 148 | static void load_unwind (void *); | ||
| 149 | 148 | ||
| 150 | /* Functions that read one byte from the current source READCHARFUN | 149 | /* Functions that read one byte from the current source READCHARFUN |
| 151 | or unreads one byte. If the integer argument C is -1, it returns | 150 | or unreads one byte. If the integer argument C is -1, it returns |
| @@ -1317,7 +1316,7 @@ Return t if the file exists and loads successfully. */) | |||
| 1317 | } | 1316 | } |
| 1318 | if (! stream) | 1317 | if (! stream) |
| 1319 | report_file_error ("Opening stdio stream", file); | 1318 | report_file_error ("Opening stdio stream", file); |
| 1320 | set_unwind_protect_ptr (fd_index, load_unwind, stream); | 1319 | set_unwind_protect_ptr (fd_index, fclose_unwind, stream); |
| 1321 | 1320 | ||
| 1322 | if (! NILP (Vpurify_flag)) | 1321 | if (! NILP (Vpurify_flag)) |
| 1323 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); | 1322 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); |
| @@ -1387,18 +1386,6 @@ Return t if the file exists and loads successfully. */) | |||
| 1387 | 1386 | ||
| 1388 | return Qt; | 1387 | return Qt; |
| 1389 | } | 1388 | } |
| 1390 | |||
| 1391 | static void | ||
| 1392 | load_unwind (void *arg) | ||
| 1393 | { | ||
| 1394 | FILE *stream = arg; | ||
| 1395 | if (stream != NULL) | ||
| 1396 | { | ||
| 1397 | block_input (); | ||
| 1398 | fclose (stream); | ||
| 1399 | unblock_input (); | ||
| 1400 | } | ||
| 1401 | } | ||
| 1402 | 1389 | ||
| 1403 | static bool | 1390 | static bool |
| 1404 | complete_filename_p (Lisp_Object pathname) | 1391 | complete_filename_p (Lisp_Object pathname) |