Now on revision 111547. ------------------------------------------------------------ revno: 111547 committer: Dmitry Antipov branch nick: trunk timestamp: Fri 2013-01-18 10:32:12 +0400 message: Fix crash when inserting data from non-regular files. See http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html for the error description produced by valgrind. * fileio.c (read_non_regular): Rename to read_contents. Free Lisp_Save_Value object used to pass parameters. (read_non_regular_quit): Rename to read_contents_quit. (Finsert_file_contents): Redesign internal file reading loop to adjust gap and end positions after each read and so help make_gap to work properly. Do not signal an I/O error too early and so do not leave not yet decoded characters in a buffer, which was the reason of redisplay crash. Use list2 to build return value. Adjust comments. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-18 05:12:08 +0000 +++ src/ChangeLog 2013-01-18 06:32:12 +0000 @@ -1,3 +1,17 @@ +2013-01-18 Dmitry Antipov + + Fix crash when inserting data from non-regular files. See + http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html + for the error description produced by valgrind. + * fileio.c (read_non_regular): Rename to read_contents. + Free Lisp_Save_Value object used to pass parameters. + (read_non_regular_quit): Rename to read_contents_quit. + (Finsert_file_contents): Redesign internal file reading loop to adjust + gap and end positions after each read and so help make_gap to work + properly. Do not signal an I/O error too early and so do not leave + not yet decoded characters in a buffer, which was the reason of + redisplay crash. Use list2 to build return value. Adjust comments. + 2013-01-17 Paul Eggert Close a race when statting and reading files (Bug#13149). === modified file 'src/fileio.c' --- src/fileio.c 2013-01-18 05:12:08 +0000 +++ src/fileio.c 2013-01-18 06:32:12 +0000 @@ -3408,13 +3408,13 @@ return Qnil; } -/* Read from a non-regular file. STATE is a Lisp_Save_Value +/* Check quit and read from the file. STATE is a Lisp_Save_Value object where slot 0 is the file descriptor, slot 1 specifies an offset to put the read bytes, and slot 2 is the maximum amount of bytes to read. Value is the number of bytes read. */ static Lisp_Object -read_non_regular (Lisp_Object state) +read_contents (Lisp_Object state) { int nbytes; @@ -3425,15 +3425,15 @@ + XSAVE_INTEGER (state, 1)), XSAVE_INTEGER (state, 2)); immediate_quit = 0; + /* Fast recycle this object for the likely next call. */ + free_misc (state); return make_number (nbytes); } - -/* Condition-case handler used when reading from non-regular files - in insert-file-contents. */ +/* Condition-case handler used when reading files in insert-file-contents. */ static Lisp_Object -read_non_regular_quit (Lisp_Object ignore) +read_contents_quit (Lisp_Object ignore) { return Qnil; } @@ -3505,7 +3505,7 @@ Lisp_Object p; ptrdiff_t total = 0; bool not_regular = 0; - int save_errno = 0; + int save_errno = 0, read_errno = 0; char read_buf[READ_BUF_SIZE]; struct coding_system coding; char buffer[1 << 14]; @@ -4195,88 +4195,72 @@ Fcons (orig_filename, Qnil)); } - /* In the following loop, HOW_MUCH contains the total bytes read so - far for a regular file, and not changed for a special file. But, - before exiting the loop, it is set to a negative value if I/O - error occurs. */ + /* In the following loop, HOW_MUCH contains the total bytes read + so far for a regular file, and not changed for a special file. */ how_much = 0; /* Total bytes inserted. */ inserted = 0; - /* Here, we don't do code conversion in the loop. It is done by - decode_coding_gap after all data are read into the buffer. */ - { - ptrdiff_t gap_size = GAP_SIZE; - - while (how_much < total) - { - /* try is reserved in some compilers (Microsoft C) */ - ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); - ptrdiff_t this; - - if (not_regular) - { - Lisp_Object nbytes; - - /* Maybe make more room. */ - if (gap_size < trytry) - { - make_gap (total - gap_size); - gap_size = GAP_SIZE; - } - - /* Read from the file, capturing `quit'. When an - error occurs, end the loop, and arrange for a quit - to be signaled after decoding the text we read. */ - nbytes = internal_condition_case_1 - (read_non_regular, - make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), - Qerror, read_non_regular_quit); - - if (NILP (nbytes)) - { - read_quit = 1; - break; - } - - this = XINT (nbytes); - } - else - { - /* Allow quitting out of the actual I/O. We don't make text - part of the buffer until all the reading is done, so a C-g - here doesn't do any harm. */ - immediate_quit = 1; - QUIT; - this = emacs_read (fd, - ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE - + inserted), - trytry); - immediate_quit = 0; - } - - if (this <= 0) - { - how_much = this; - break; - } - - gap_size -= this; - - /* For a regular file, where TOTAL is the real size, - count HOW_MUCH to compare with it. - For a special file, where TOTAL is just a buffer size, - so don't bother counting in HOW_MUCH. - (INSERTED is where we count the number of characters inserted.) */ - if (! not_regular) - how_much += this; - inserted += this; - } - } - - /* Now we have read all the file data into the gap. - If it was empty, undo marking the buffer modified. */ + /* Here we don't do code conversion in the loop. It is done by + decode_coding_gap after all data are read into the buffer, or + reading loop is interrupted with quit or due to I/O error. */ + + while (how_much < total) + { + ptrdiff_t nread, maxread = min (total - how_much, READ_BUF_SIZE); + Lisp_Object result; + + /* For a special file, gap is enlarged as we read, + so GAP_SIZE should be checked every time. */ + if (not_regular && (GAP_SIZE < maxread)) + make_gap (maxread - GAP_SIZE); + + /* Read from the file, capturing `quit'. */ + result = internal_condition_case_1 + (read_contents, + make_save_value ("iii", (ptrdiff_t) fd, inserted, maxread), + Qerror, read_contents_quit); + if (NILP (result)) + { + /* Quit is signaled. End the loop and arrange + real quit after decoding the text we read. */ + read_quit = 1; + break; + } + nread = XINT (result); + if (nread <= 0) + { + /* End of file or I/O error. End the loop and + save error code in case of I/O error. */ + if (nread < 0) + read_errno = errno; + break; + } + + /* Adjust gap and end positions. */ + GAP_SIZE -= nread; + GPT += nread; + ZV += nread; + Z += nread; + GPT_BYTE += nread; + ZV_BYTE += nread; + Z_BYTE += nread; + if (GAP_SIZE > 0) + *(GPT_ADDR) = 0; + + /* For a regular file, where TOTAL is the real size, count HOW_MUCH to + compare with it. For a special file, where TOTAL is just a buffer + size, don't bother counting in HOW_MUCH, but always accumulate the + number of bytes read in INSERTED. */ + if (!not_regular) + how_much += nread; + inserted += nread; + } + + /* Now we have either read all the file data into the gap, + or stop reading on I/O error or quit. If nothing was + read, undo marking the buffer modified. */ if (inserted == 0) { @@ -4289,28 +4273,11 @@ else Vdeactivate_mark = Qt; - /* Make the text read part of the buffer. */ - GAP_SIZE -= inserted; - GPT += inserted; - GPT_BYTE += inserted; - ZV += inserted; - ZV_BYTE += inserted; - Z += inserted; - Z_BYTE += inserted; - - if (GAP_SIZE > 0) - /* Put an anchor to ensure multi-byte form ends at gap. */ - *GPT_ADDR = 0; - emacs_close (fd); /* Discard the unwind protect for closing the file. */ specpdl_ptr--; - if (how_much < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); - notfound: if (NILP (coding_system)) @@ -4599,14 +4566,17 @@ report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); } + /* There was an error reading file. */ + if (read_errno) + error ("IO error reading %s: %s", + SDATA (orig_filename), emacs_strerror (read_errno)); + + /* Quit was signaled. */ if (read_quit) Fsignal (Qquit, Qnil); - /* ??? Retval needs to be dealt with in all cases consistently. */ if (NILP (val)) - val = Fcons (orig_filename, - Fcons (make_number (inserted), - Qnil)); + val = list2 (orig_filename, make_number (inserted)); RETURN_UNGCPRO (unbind_to (count, val)); } ------------------------------------------------------------ revno: 111546 fixes bug: http://debbugs.gnu.org/13149 committer: Paul Eggert branch nick: trunk timestamp: Thu 2013-01-17 21:12:08 -0800 message: Close a race when statting and reading files. * fileio.c (Finsert_file_contents): Use open+fstat, not stat+open. This avoids a race if the file is renamed between stat and open. This race is not the problem originally noted in Bug#13149; see and later messages in the thread. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-17 06:29:40 +0000 +++ src/ChangeLog 2013-01-18 05:12:08 +0000 @@ -1,3 +1,11 @@ +2013-01-17 Paul Eggert + + Close a race when statting and reading files (Bug#13149). + * fileio.c (Finsert_file_contents): Use open+fstat, not stat+open. + This avoids a race if the file is renamed between stat and open. + This race is not the problem originally noted in Bug#13149; + see and later messages in the thread. + 2013-01-17 Dmitry Antipov * lisp.h (toplevel): Add comment about using Lisp_Save_Value === modified file 'src/fileio.c' --- src/fileio.c 2013-01-17 06:29:40 +0000 +++ src/fileio.c 2013-01-18 05:12:08 +0000 @@ -3492,7 +3492,6 @@ (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace) { struct stat st; - int file_status; EMACS_TIME mtime; int fd; ptrdiff_t inserted = 0; @@ -3554,26 +3553,9 @@ orig_filename = filename; filename = ENCODE_FILE (filename); - fd = -1; - -#ifdef WINDOWSNT - { - Lisp_Object tem = Vw32_get_true_file_attributes; - - /* Tell stat to use expensive method to get accurate info. */ - Vw32_get_true_file_attributes = Qt; - file_status = stat (SSDATA (filename), &st); - Vw32_get_true_file_attributes = tem; - } -#else - file_status = stat (SSDATA (filename), &st); -#endif /* WINDOWSNT */ - - if (file_status == 0) - mtime = get_stat_mtime (&st); - else + fd = emacs_open (SSDATA (filename), O_RDONLY, 0); + if (fd < 0) { - badopen: save_errno = errno; if (NILP (visit)) report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); @@ -3585,6 +3567,17 @@ goto notfound; } + /* Replacement should preserve point as it preserves markers. */ + if (!NILP (replace)) + record_unwind_protect (restore_point_unwind, Fpoint_marker ()); + + record_unwind_protect (close_file_unwind, make_number (fd)); + + if (fstat (fd, &st) != 0) + report_file_error ("Getting input file status", + Fcons (orig_filename, Qnil)); + mtime = get_stat_mtime (&st); + /* This code will need to be changed in order to work on named pipes, and it's probably just not worth it. So we should at least signal an error. */ @@ -3600,17 +3593,6 @@ build_string ("not a regular file"), orig_filename); } - if (fd < 0) - if ((fd = emacs_open (SSDATA (filename), O_RDONLY, 0)) < 0) - goto badopen; - - /* Replacement should preserve point as it preserves markers. */ - if (!NILP (replace)) - record_unwind_protect (restore_point_unwind, Fpoint_marker ()); - - record_unwind_protect (close_file_unwind, make_number (fd)); - - if (!NILP (visit)) { if (!NILP (beg) || !NILP (end)) ------------------------------------------------------------ revno: 111545 committer: Michael Albinus branch nick: trunk timestamp: Thu 2013-01-17 20:12:40 +0100 message: * autorevert.el (auto-revert-notify-watch-descriptor): Make it buffer local, again. This was lost with the fix on 2013-01-12. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-01-17 10:01:33 +0000 +++ lisp/ChangeLog 2013-01-17 19:12:40 +0000 @@ -1,3 +1,8 @@ +2013-01-17 Michael Albinus + + * autorevert.el (auto-revert-notify-watch-descriptor): Make it + buffer local, again. This was lost with the fix on 2013-01-12. + 2013-01-17 Jürgen Hötzel * eshell/esh-util.el (eshell-path-env): Make it buffer local, in === modified file 'lisp/autorevert.el' --- lisp/autorevert.el 2013-01-17 09:06:47 +0000 +++ lisp/autorevert.el 2013-01-17 19:12:40 +0000 @@ -310,6 +310,7 @@ (defvar auto-revert-notify-watch-descriptor nil "The file watch descriptor active for the current buffer.") +(make-variable-buffer-local 'auto-revert-notify-watch-descriptor) (put 'auto-revert-notify-watch-descriptor 'permanent-local t) (defvar auto-revert-notify-modified-p nil ------------------------------------------------------------ revno: 111544 committer: Glenn Morris branch nick: trunk timestamp: Thu 2013-01-17 06:17:35 -0500 message: Auto-commit of generated files. diff: === modified file 'autogen/config.in' --- autogen/config.in 2013-01-12 11:17:37 +0000 +++ autogen/config.in 2013-01-17 11:17:35 +0000 @@ -1441,10 +1441,8 @@ /* Define if the system is AIX. */ #undef _AIX -/* Enable large inode numbers on Mac OS X. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif +/* Enable large inode numbers on Mac OS X 10.5. */ +#undef _DARWIN_USE_64_BIT_INODE /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS === modified file 'autogen/configure' --- autogen/configure 2013-01-16 11:17:35 +0000 +++ autogen/configure 2013-01-17 11:17:35 +0000 @@ -6714,6 +6714,8 @@ fi +$as_echo "#define _DARWIN_USE_64_BIT_INODE 1" >>confdefs.h + fi case $ac_cv_prog_cc_stdc in #( ------------------------------------------------------------ revno: 111543 author: Jürgen Hötzel committer: Michael Albinus + + * eshell/esh-util.el (eshell-path-env): Make it buffer local, in + order to support several eshell buffers in parallel. + 2013-01-17 Michael Albinus * autorevert.el (auto-revert-use-notify): In the :set function, do === modified file 'lisp/eshell/esh-util.el' --- lisp/eshell/esh-util.el 2013-01-01 09:11:05 +0000 +++ lisp/eshell/esh-util.el 2013-01-17 10:01:33 +0000 @@ -229,6 +229,7 @@ "Content of $PATH. It might be different from \(getenv \"PATH\"\), when `default-directory' points to a remote host.") +(make-variable-buffer-local 'eshell-path-env) (defun eshell-parse-colon-path (path-env) "Split string with `parse-colon-path'. ------------------------------------------------------------ revno: 111542 committer: Michael Albinus + + * autorevert.el (auto-revert-use-notify): In the :set function, do + not modify `kill-buffer-hook'. + (auto-revert-notify-rm-watch): Remove + `auto-revert-notify-rm-watch' from `kill-buffer-hook'. + (auto-revert-notify-add-watch): Do not call + `auto-revert-notify-rm-watch', but add it to a buffer local + `kill-buffer-hook'. + 2013-01-16 Stefan Monnier * emacs-lisp/trace.el (trace--read-args): Use a closure and an honest === modified file 'lisp/autorevert.el' --- lisp/autorevert.el 2013-01-12 19:24:27 +0000 +++ lisp/autorevert.el 2013-01-17 09:06:47 +0000 @@ -273,13 +273,12 @@ :type 'boolean :set (lambda (variable value) (set-default variable (and auto-revert-notify-enabled value)) - (if (symbol-value variable) - (add-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch) - (remove-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch) + (unless (symbol-value variable) (when auto-revert-notify-enabled (dolist (buf (buffer-list)) (with-current-buffer buf - (auto-revert-notify-rm-watch)))))) + (when (symbol-value 'auto-revert-notify-watch-descriptor) + (auto-revert-notify-rm-watch))))))) :version "24.4") ;; Internal variables: @@ -472,14 +471,15 @@ 'inotify-rm-watch 'w32notify-rm-watch) auto-revert-notify-watch-descriptor)) (remhash auto-revert-notify-watch-descriptor - auto-revert-notify-watch-descriptor-hash-list)) + auto-revert-notify-watch-descriptor-hash-list) + (remove-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch)) (setq auto-revert-notify-watch-descriptor nil auto-revert-notify-modified-p nil)) (defun auto-revert-notify-add-watch () "Enable file watch for current buffer's associated file." - (when (and buffer-file-name auto-revert-use-notify) - (auto-revert-notify-rm-watch) + (when (and buffer-file-name auto-revert-use-notify + (not auto-revert-notify-watch-descriptor)) (let ((func (if (fboundp 'inotify-add-watch) 'inotify-add-watch 'w32notify-add-watch)) (aspect (if (fboundp 'inotify-add-watch) @@ -489,9 +489,12 @@ (funcall func buffer-file-name aspect 'auto-revert-notify-handler))) (if auto-revert-notify-watch-descriptor - (puthash auto-revert-notify-watch-descriptor - (current-buffer) - auto-revert-notify-watch-descriptor-hash-list) + (progn + (puthash auto-revert-notify-watch-descriptor + (current-buffer) + auto-revert-notify-watch-descriptor-hash-list) + (add-hook (make-local-variable 'kill-buffer-hook) + 'auto-revert-notify-rm-watch)) ;; Fallback to file checks. (set (make-local-variable 'auto-revert-use-notify) nil))))) ------------------------------------------------------------ revno: 111541 committer: Dmitry Antipov branch nick: trunk timestamp: Thu 2013-01-17 10:29:40 +0400 message: * lisp.h (toplevel): Add comment about using Lisp_Save_Value objects, related functions and macros. (make_save_value): Adjust prototype. (make_save_pointer): New prototype. (SAFE_NALLOCA): Fix indentation. Use make_save_pointer. (SAFE_ALLOCA_LISP): Adjust make_save_value usage. * alloc.c (format_save_value): Rename to make_save_value. (make_save_pointer): New function. (record_xmalloc): Use make_save_pointer. * dired.c, editfns.c, fileio.c, font.c, gtkutil.c, lread.c: * nsmenu.m, nsterm.m, xfns.c, xmenu.c, xselect.c, keymap.c: Change users of make_save_value to make_save_pointer. Likewise for format_save_value and make_save_value. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-01-17 05:52:13 +0000 +++ src/ChangeLog 2013-01-17 06:29:40 +0000 @@ -1,5 +1,21 @@ 2013-01-17 Dmitry Antipov + * lisp.h (toplevel): Add comment about using Lisp_Save_Value + objects, related functions and macros. + (make_save_value): Adjust prototype. + (make_save_pointer): New prototype. + (SAFE_NALLOCA): Fix indentation. Use make_save_pointer. + (SAFE_ALLOCA_LISP): Adjust make_save_value usage. + * alloc.c (format_save_value): Rename to make_save_value. + (make_save_pointer): New function. + (record_xmalloc): Use make_save_pointer. + * dired.c, editfns.c, fileio.c, font.c, gtkutil.c, lread.c: + * nsmenu.m, nsterm.m, xfns.c, xmenu.c, xselect.c, keymap.c: + Change users of make_save_value to make_save_pointer. + Likewise for format_save_value and make_save_value. + +2013-01-17 Dmitry Antipov + * buffer.h (NARROWED, BUF_NARROWED): Drop unused macros. (DECODE_POSITION, BUFFER_CHECK_INDIRECTION): Fix indentation. * buffer.c (toplevel, syms_of_buffer): Drop old commented-out === modified file 'src/alloc.c' --- src/alloc.c 2013-01-15 21:38:58 +0000 +++ src/alloc.c 2013-01-17 06:29:40 +0000 @@ -845,7 +845,7 @@ record_xmalloc (size_t size) { void *p = xmalloc (size); - record_unwind_protect (safe_alloca_unwind, make_save_value (p, 0)); + record_unwind_protect (safe_alloca_unwind, make_save_pointer (p)); return p; } @@ -3356,7 +3356,7 @@ and `o' for Lisp_Object. Up to 4 objects can be specified. */ Lisp_Object -format_save_value (const char *fmt, ...) +make_save_value (const char *fmt, ...) { va_list ap; int len = strlen (fmt); @@ -3404,15 +3404,19 @@ return val; } -/* Return a Lisp_Save_Value object containing POINTER and INTEGER. - Most code should use this to package C integers and pointers - to call record_unwind_protect. The unwind function can get the - C values back using XSAVE_POINTER and XSAVE_INTEGER. */ +/* The most common task it to save just one C pointer. */ Lisp_Object -make_save_value (void *pointer, ptrdiff_t integer) +make_save_pointer (void *pointer) { - return format_save_value ("pi", pointer, integer); + Lisp_Object val = allocate_misc (Lisp_Misc_Save_Value); + struct Lisp_Save_Value *p = XSAVE_VALUE (val); + + p->area = 0; + p->type0 = SAVE_POINTER; + p->data[0].pointer = pointer; + p->type1 = p->type2 = p->type3 = SAVE_UNUSED; + return val; } /* Free a Lisp_Save_Value object. Do not use this function === modified file 'src/dired.c' --- src/dired.c 2013-01-15 09:22:25 +0000 +++ src/dired.c 2013-01-17 06:29:40 +0000 @@ -152,7 +152,7 @@ file-attributes on filenames, both of which can throw, so we must do a proper unwind-protect. */ record_unwind_protect (directory_files_internal_unwind, - make_save_value (d, 0)); + make_save_pointer (d)); #ifdef WINDOWSNT if (attrs) @@ -465,7 +465,7 @@ report_file_error ("Opening directory", Fcons (dirname, Qnil)); record_unwind_protect (directory_files_internal_unwind, - make_save_value (d, 0)); + make_save_pointer (d)); /* Loop reading blocks */ /* (att3b compiler bug requires do a null comparison this way) */ === modified file 'src/editfns.c' --- src/editfns.c 2013-01-15 09:22:25 +0000 +++ src/editfns.c 2013-01-17 06:29:40 +0000 @@ -833,7 +833,7 @@ Lisp_Object save_excursion_save (void) { - return format_save_value + return make_save_value ("oooo", Fpoint_marker (), /* Do not copy the mark if it points to nowhere. */ @@ -4249,7 +4249,7 @@ { buf = xmalloc (bufsize); sa_must_free = 1; - buf_save_value = make_save_value (buf, 0); + buf_save_value = make_save_pointer (buf); record_unwind_protect (safe_alloca_unwind, buf_save_value); memcpy (buf, initial_buffer, used); } === modified file 'src/fileio.c' --- src/fileio.c 2013-01-15 10:14:31 +0000 +++ src/fileio.c 2013-01-17 06:29:40 +0000 @@ -4249,7 +4249,7 @@ to be signaled after decoding the text we read. */ nbytes = internal_condition_case_1 (read_non_regular, - format_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), + make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), Qerror, read_non_regular_quit); if (NILP (nbytes)) @@ -5608,7 +5608,7 @@ } record_unwind_protect (do_auto_save_unwind, - make_save_value (stream, 0)); + make_save_pointer (stream)); record_unwind_protect (do_auto_save_unwind_1, make_number (minibuffer_auto_raise)); minibuffer_auto_raise = 0; === modified file 'src/font.c' --- src/font.c 2013-01-15 09:22:25 +0000 +++ src/font.c 2013-01-17 06:29:40 +0000 @@ -1861,7 +1861,7 @@ else { otf = STRINGP (file) ? OTF_open (SSDATA (file)) : NULL; - val = make_save_value (otf, 0); + val = make_save_pointer (otf); otf_list = Fcons (Fcons (file, val), otf_list); } return otf; === modified file 'src/ftfont.c' --- src/ftfont.c 2013-01-15 09:22:25 +0000 +++ src/ftfont.c 2013-01-17 06:29:40 +0000 @@ -393,7 +393,7 @@ cache_data = xmalloc (sizeof *cache_data); cache_data->ft_face = NULL; cache_data->fc_charset = NULL; - val = make_save_value (cache_data, 0); + val = make_save_value ("pi", cache_data, 0); cache = Fcons (Qnil, val); Fputhash (key, cache, ft_face_cache); } === modified file 'src/gtkutil.c' --- src/gtkutil.c 2013-01-15 09:22:25 +0000 +++ src/gtkutil.c 2013-01-17 06:29:40 +0000 @@ -1716,7 +1716,7 @@ g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL); gtk_widget_show (w); - record_unwind_protect (pop_down_dialog, make_save_value (&dd, 0)); + record_unwind_protect (pop_down_dialog, make_save_pointer (&dd)); (void) xg_maybe_add_timer (&dd); g_main_loop_run (dd.loop); === modified file 'src/keymap.c' --- src/keymap.c 2013-01-15 10:14:31 +0000 +++ src/keymap.c 2013-01-17 06:29:40 +0000 @@ -610,7 +610,7 @@ } else if (CHAR_TABLE_P (binding)) map_char_table (map_keymap_char_table_item, Qnil, binding, - format_save_value ("ppo", fun, data, args)); + make_save_value ("ppo", fun, data, args)); } UNGCPRO; return tail; === modified file 'src/lisp.h' --- src/lisp.h 2013-01-15 21:38:58 +0000 +++ src/lisp.h 2013-01-17 06:29:40 +0000 @@ -1388,7 +1388,50 @@ SAVE_OBJECT }; -/* Special object used to hold a different values for later use. */ +/* Special object used to hold a different values for later use. + + This is mostly used to package C integers and pointers to call + record_unwind_protect. Typical task is to pass just one C pointer + to unwind function. You should pack pointer with make_save_pointer + and then get it back with XSAVE_POINTER, e.g.: + + ... + struct my_data *md = get_my_data (); + record_unwind_protect (my_unwind, make_save_pointer (md)); + ... + + Lisp_Object my_unwind (Lisp_Object arg) + { + struct my_data *md = XSAVE_POINTER (arg, 0); + ... + } + + If yon need to pass more than just one C pointer, you should + use make_save_value. This function allows you to pack up to + 4 integers, pointers or Lisp_Objects and conveniently get them + back with XSAVE_POINTER, XSAVE_INTEGER and XSAVE_OBJECT macros: + + ... + struct my_data *md = get_my_data (); + ptrdiff_t my_offset = get_my_offset (); + Lisp_Object my_object = get_my_object (); + record_unwind_protect + (my_unwind, make_save_value ("pio", md, my_offset, my_object)); + ... + + Lisp_Object my_unwind (Lisp_Object arg) + { + struct my_data *md = XSAVE_POINTER (arg, 0); + ptrdiff_t my_offset = XSAVE_INTEGER (arg, 1); + Lisp_Object my_object = XSAVE_OBJECT (arg, 2); + ... + } + + If ENABLE_CHECKING is in effect, XSAVE_xxx macros do type checking of the + saved objects and raise eassert if type of the saved object doesn't match + the type which is extracted. In the example above, XSAVE_INTEGER (arg, 2) + or XSAVE_OBJECT (arg, 1) are wrong because integer was saved in slot 1 and + Lisp_Object was saved in slot 2 of ARG. */ struct Lisp_Save_Value { @@ -3018,8 +3061,8 @@ extern Lisp_Object make_float (double); extern void display_malloc_warning (void); extern ptrdiff_t inhibit_garbage_collection (void); -extern Lisp_Object format_save_value (const char *, ...); -extern Lisp_Object make_save_value (void *, ptrdiff_t); +extern Lisp_Object make_save_value (const char *, ...); +extern Lisp_Object make_save_pointer (void *); extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); extern void free_marker (Lisp_Object); extern void free_cons (struct Lisp_Cons *); @@ -3701,16 +3744,16 @@ NITEMS items, each of the same type as *BUF. MULTIPLIER must positive. The code is tuned for MULTIPLIER being a constant. */ -#define SAFE_NALLOCA(buf, multiplier, nitems) \ - do { \ - if ((nitems) <= MAX_ALLOCA / sizeof *(buf) / (multiplier)) \ - (buf) = alloca (sizeof *(buf) * (multiplier) * (nitems)); \ - else \ +#define SAFE_NALLOCA(buf, multiplier, nitems) \ + do { \ + if ((nitems) <= MAX_ALLOCA / sizeof *(buf) / (multiplier)) \ + (buf) = alloca (sizeof *(buf) * (multiplier) * (nitems)); \ + else \ { \ (buf) = xnmalloc (nitems, sizeof *(buf) * (multiplier)); \ sa_must_free = 1; \ record_unwind_protect (safe_alloca_unwind, \ - make_save_value (buf, 0)); \ + make_save_pointer (buf)); \ } \ } while (0) @@ -3735,7 +3778,7 @@ { \ Lisp_Object arg_; \ buf = xmalloc ((nelt) * word_size); \ - arg_ = make_save_value (buf, nelt); \ + arg_ = make_save_value ("pi", buf, nelt); \ XSAVE_VALUE (arg_)->area = 1; \ sa_must_free = 1; \ record_unwind_protect (safe_alloca_unwind, arg_); \ === modified file 'src/lread.c' --- src/lread.c 2013-01-15 09:22:25 +0000 +++ src/lread.c 2013-01-17 06:29:40 +0000 @@ -1298,7 +1298,7 @@ message_with_string ("Loading %s...", file, 1); } - record_unwind_protect (load_unwind, make_save_value (stream, 0)); + record_unwind_protect (load_unwind, make_save_pointer (stream)); record_unwind_protect (load_descriptor_unwind, load_descriptor_list); specbind (Qload_file_name, found); specbind (Qinhibit_file_name_operation, Qnil); === modified file 'src/nsmenu.m' --- src/nsmenu.m 2013-01-15 09:22:25 +0000 +++ src/nsmenu.m 2013-01-17 06:29:40 +0000 @@ -1440,7 +1440,7 @@ unwind_data->pool = pool; unwind_data->dialog = dialog; - record_unwind_protect (pop_down_menu, make_save_value (unwind_data, 0)); + record_unwind_protect (pop_down_menu, make_save_pointer (unwind_data)); popup_activated_flag = 1; tem = [dialog runDialogAt: p]; unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */ === modified file 'src/nsterm.m' --- src/nsterm.m 2013-01-13 12:08:31 +0000 +++ src/nsterm.m 2013-01-17 06:29:40 +0000 @@ -3677,7 +3677,7 @@ } bar = [[EmacsScroller alloc] initFrame: r window: win]; - wset_vertical_scroll_bar (window, make_save_value (bar, 0)); + wset_vertical_scroll_bar (window, make_save_pointer (bar)); } else { === modified file 'src/xfns.c' --- src/xfns.c 2013-01-15 09:22:25 +0000 +++ src/xfns.c 2013-01-17 06:29:40 +0000 @@ -5416,7 +5416,7 @@ XmStringFree (default_xmstring); } - record_unwind_protect (clean_up_file_dialog, make_save_value (dialog, 0)); + record_unwind_protect (clean_up_file_dialog, make_save_pointer (dialog)); /* Process events until the user presses Cancel or OK. */ x_menu_set_in_use (1); === modified file 'src/xmenu.c' --- src/xmenu.c 2013-01-15 10:14:31 +0000 +++ src/xmenu.c 2013-01-17 06:29:40 +0000 @@ -1477,7 +1477,7 @@ gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, timestamp ? timestamp : gtk_get_current_event_time ()); - record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); + record_unwind_protect (pop_down_menu, make_save_pointer (menu)); if (gtk_widget_get_mapped (menu)) { @@ -1826,7 +1826,7 @@ /* Make sure to free the widget_value objects we used to specify the contents even with longjmp. */ record_unwind_protect (cleanup_widget_value_tree, - make_save_value (first_wv, 0)); + make_save_pointer (first_wv)); /* Actually create and show the menu until popped down. */ create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp); @@ -1925,7 +1925,7 @@ if (menu) { ptrdiff_t specpdl_count = SPECPDL_INDEX (); - record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); + record_unwind_protect (pop_down_menu, make_save_pointer (menu)); /* Display the menu. */ gtk_widget_show_all (menu); @@ -2136,7 +2136,7 @@ /* Make sure to free the widget_value objects we used to specify the contents even with longjmp. */ record_unwind_protect (cleanup_widget_value_tree, - make_save_value (first_wv, 0)); + make_save_pointer (first_wv)); /* Actually create and show the dialog. */ create_and_show_dialog (f, first_wv); @@ -2479,7 +2479,7 @@ #endif record_unwind_protect (pop_down_menu, - format_save_value ("pp", f, menu)); + make_save_value ("pp", f, menu)); /* Help display under X won't work because XMenuActivate contains a loop that doesn't give Emacs a chance to process it. */ === modified file 'src/xselect.c' --- src/xselect.c 2013-01-15 09:22:25 +0000 +++ src/xselect.c 2013-01-17 06:29:40 +0000 @@ -1141,7 +1141,7 @@ /* Make sure to do unexpect_property_change if we quit or err. */ record_unwind_protect (wait_for_property_change_unwind, - make_save_value (location, 0)); + make_save_pointer (location)); XSETCAR (property_change_reply, Qnil); property_change_reply_object = location;