diff options
| author | Paul Eggert | 2013-07-16 14:49:32 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-07-16 14:49:32 -0700 |
| commit | 41d48a42df6ce4e5af9543f97313e256f16aa900 (patch) | |
| tree | 2c23587c2691d181eb1561ee7347924887f73e53 /src | |
| parent | 27e498e6e5fea8ac64c90ac13678b537b7b12302 (diff) | |
| download | emacs-41d48a42df6ce4e5af9543f97313e256f16aa900.tar.gz emacs-41d48a42df6ce4e5af9543f97313e256f16aa900.zip | |
Fix bug where insert-file-contents closes a file twice.
* fileio.c (close_file_unwind): Don't close if FD is negative;
this can happen when unwinding a zapped file descriptor.
(Finsert_file_contents): Unwind-protect the fd before the point marker,
in case Emacs runs out of memory between the two unwind-protects.
Don't trash errno when closing FD.
Zap the FD in the specpdl when closing it, instead of deferring
the removal of the unwind-protect; this fixes a bug where a child
function unwinds the stack past us.
Fixes: debbugs:14839
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/fileio.c | 28 | ||||
| -rw-r--r-- | src/lisp.h | 6 |
3 files changed, 25 insertions, 19 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 8474e8aa5e4..ab90682aa67 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,15 @@ | |||
| 1 | 2013-07-16 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2013-07-16 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Fix bug where Emacs tries to close a file twice (Bug#14839). | ||
| 4 | * fileio.c (close_file_unwind): Don't close if FD is negative; | ||
| 5 | this can happen when unwinding a zapped file descriptor. | ||
| 6 | (Finsert_file_contents): Unwind-protect the fd before the point marker, | ||
| 7 | in case Emacs runs out of memory between the two unwind-protects. | ||
| 8 | Don't trash errno when closing FD. | ||
| 9 | Zap the FD in the specpdl when closing it, instead of deferring | ||
| 10 | the removal of the unwind-protect; this fixes a bug where a child | ||
| 11 | function unwinds the stack past us. | ||
| 12 | |||
| 3 | New unwind-protect flavors to better type-check C callbacks. | 13 | New unwind-protect flavors to better type-check C callbacks. |
| 4 | This also lessens the need to write wrappers for callbacks, | 14 | This also lessens the need to write wrappers for callbacks, |
| 5 | and the need for make_save_pointer. | 15 | and the need for make_save_pointer. |
diff --git a/src/fileio.c b/src/fileio.c index 1b5208e5f25..b74b0ca91c2 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -215,7 +215,8 @@ report_file_error (char const *string, Lisp_Object name) | |||
| 215 | void | 215 | void |
| 216 | close_file_unwind (int fd) | 216 | close_file_unwind (int fd) |
| 217 | { | 217 | { |
| 218 | emacs_close (fd); | 218 | if (0 <= fd) |
| 219 | emacs_close (fd); | ||
| 219 | } | 220 | } |
| 220 | 221 | ||
| 221 | /* Restore point, having saved it as a marker. */ | 222 | /* Restore point, having saved it as a marker. */ |
| @@ -3514,7 +3515,7 @@ by calling `format-decode', which see. */) | |||
| 3514 | && BEG == Z); | 3515 | && BEG == Z); |
| 3515 | Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; | 3516 | Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; |
| 3516 | bool we_locked_file = 0; | 3517 | bool we_locked_file = 0; |
| 3517 | bool deferred_remove_unwind_protect = 0; | 3518 | ptrdiff_t fd_index; |
| 3518 | 3519 | ||
| 3519 | if (current_buffer->base_buffer && ! NILP (visit)) | 3520 | if (current_buffer->base_buffer && ! NILP (visit)) |
| 3520 | error ("Cannot do file visiting in an indirect buffer"); | 3521 | error ("Cannot do file visiting in an indirect buffer"); |
| @@ -3565,12 +3566,13 @@ by calling `format-decode', which see. */) | |||
| 3565 | goto notfound; | 3566 | goto notfound; |
| 3566 | } | 3567 | } |
| 3567 | 3568 | ||
| 3569 | fd_index = SPECPDL_INDEX (); | ||
| 3570 | record_unwind_protect_int (close_file_unwind, fd); | ||
| 3571 | |||
| 3568 | /* Replacement should preserve point as it preserves markers. */ | 3572 | /* Replacement should preserve point as it preserves markers. */ |
| 3569 | if (!NILP (replace)) | 3573 | if (!NILP (replace)) |
| 3570 | record_unwind_protect (restore_point_unwind, Fpoint_marker ()); | 3574 | record_unwind_protect (restore_point_unwind, Fpoint_marker ()); |
| 3571 | 3575 | ||
| 3572 | record_unwind_protect_int (close_file_unwind, fd); | ||
| 3573 | |||
| 3574 | if (fstat (fd, &st) != 0) | 3576 | if (fstat (fd, &st) != 0) |
| 3575 | report_file_error ("Input file status", orig_filename); | 3577 | report_file_error ("Input file status", orig_filename); |
| 3576 | mtime = get_stat_mtime (&st); | 3578 | mtime = get_stat_mtime (&st); |
| @@ -4015,15 +4017,10 @@ by calling `format-decode', which see. */) | |||
| 4015 | memcpy (read_buf, coding.carryover, unprocessed); | 4017 | memcpy (read_buf, coding.carryover, unprocessed); |
| 4016 | } | 4018 | } |
| 4017 | UNGCPRO; | 4019 | UNGCPRO; |
| 4018 | emacs_close (fd); | ||
| 4019 | |||
| 4020 | /* We should remove the unwind_protect calling | ||
| 4021 | close_file_unwind, but other stuff has been added the stack, | ||
| 4022 | so defer the removal till we reach the `handled' label. */ | ||
| 4023 | deferred_remove_unwind_protect = 1; | ||
| 4024 | |||
| 4025 | if (this < 0) | 4020 | if (this < 0) |
| 4026 | report_file_error ("Read error", orig_filename); | 4021 | report_file_error ("Read error", orig_filename); |
| 4022 | emacs_close (fd); | ||
| 4023 | set_unwind_protect_int (fd_index, -1); | ||
| 4027 | 4024 | ||
| 4028 | if (unprocessed > 0) | 4025 | if (unprocessed > 0) |
| 4029 | { | 4026 | { |
| @@ -4264,9 +4261,7 @@ by calling `format-decode', which see. */) | |||
| 4264 | Vdeactivate_mark = Qt; | 4261 | Vdeactivate_mark = Qt; |
| 4265 | 4262 | ||
| 4266 | emacs_close (fd); | 4263 | emacs_close (fd); |
| 4267 | 4264 | set_unwind_protect_int (fd_index, -1); | |
| 4268 | /* Discard the unwind protect for closing the file. */ | ||
| 4269 | specpdl_ptr--; | ||
| 4270 | 4265 | ||
| 4271 | if (how_much < 0) | 4266 | if (how_much < 0) |
| 4272 | report_file_error ("Read error", orig_filename); | 4267 | report_file_error ("Read error", orig_filename); |
| @@ -4393,11 +4388,6 @@ by calling `format-decode', which see. */) | |||
| 4393 | 4388 | ||
| 4394 | handled: | 4389 | handled: |
| 4395 | 4390 | ||
| 4396 | if (deferred_remove_unwind_protect) | ||
| 4397 | /* If requested above, discard the unwind protect for closing the | ||
| 4398 | file. */ | ||
| 4399 | specpdl_ptr--; | ||
| 4400 | |||
| 4401 | if (!NILP (visit)) | 4391 | if (!NILP (visit)) |
| 4402 | { | 4392 | { |
| 4403 | if (empty_undo_list_p) | 4393 | if (empty_undo_list_p) |
diff --git a/src/lisp.h b/src/lisp.h index 38413f831dc..26e9e18ec9a 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2750,6 +2750,12 @@ set_unwind_protect_ptr (ptrdiff_t count, void *arg) | |||
| 2750 | specpdl[count].unwind_ptr.arg = arg; | 2750 | specpdl[count].unwind_ptr.arg = arg; |
| 2751 | } | 2751 | } |
| 2752 | 2752 | ||
| 2753 | LISP_INLINE void | ||
| 2754 | set_unwind_protect_int (ptrdiff_t count, int arg) | ||
| 2755 | { | ||
| 2756 | specpdl[count].unwind_int.arg = arg; | ||
| 2757 | } | ||
| 2758 | |||
| 2753 | /* Everything needed to describe an active condition case. | 2759 | /* Everything needed to describe an active condition case. |
| 2754 | 2760 | ||
| 2755 | Members are volatile if their values need to survive _longjmp when | 2761 | Members are volatile if their values need to survive _longjmp when |