commit 085929ca9309a170b5b4252448f1291e3db2b594 (HEAD, refs/remotes/origin/master) Author: YAMAMOTO Mitsuharu Date: Tue Apr 23 17:27:04 2019 +0900 Release xft_data in widget destroy callback to avoid visual distraction * lwlib/lwlib-int.h (struct _widget_instance) [HAVE_XFT]: Remove nr_xft_data. * lwlib/lwlib-Xaw.c (find_xft_data, xaw_update_one_widget) [HAVE_XFT]: Loop while widget member is not NULL instead of using nr_xft_data. (xaw_destroy_instance) [HAVE_XFT]: Move xft_data release code from here ... (destroy_xft_data) [HAVE_XFT]: ... to here. (make_dialog) [HAVE_XFT]: Add destroy_xft_data as destroy callback for dialog. diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c index 9655076da9..a00f8aa73f 100644 --- a/lwlib/lwlib-Xaw.c +++ b/lwlib/lwlib-Xaw.c @@ -113,6 +113,23 @@ fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font) data->p_width = data->p_height = 0; } +static void +destroy_xft_data (Widget widget, XtPointer closure, XtPointer call_data) +{ + struct widget_xft_data *xft_data = closure; + + for (int i = 0; xft_data[i].widget; ++i) + { + if (xft_data[i].xft_draw) + XftDrawDestroy (xft_data[i].xft_draw); + if (xft_data[i].p != None) + XFreePixmap (XtDisplay (widget), xft_data[i].p); + } + if (xft_data[0].xft_font) + XftFontClose (XtDisplay (widget), xft_data[0].xft_font); + xfree (xft_data); +} + static XftFont* openFont (Widget widget, char *name) { @@ -230,7 +247,7 @@ find_xft_data (Widget widget) } if (!inst || !inst->xft_data || !inst->xft_data[0].xft_font) return 0; - for (nr = 0; data == NULL && nr < inst->nr_xft_data; ++nr) + for (nr = 0; data == NULL && inst->xft_data[nr].widget; ++nr) { if (inst->xft_data[nr].widget == widget) data = &inst->xft_data[nr]; @@ -327,10 +344,10 @@ xaw_update_one_widget (widget_instance *instance, { int th; int nr; - for (nr = 0; nr < instance->nr_xft_data; ++nr) + for (nr = 0; instance->xft_data[nr].widget; ++nr) if (instance->xft_data[nr].widget == widget) break; - if (nr < instance->nr_xft_data) + if (instance->xft_data[nr].widget) { set_text (&instance->xft_data[nr], instance->parent, val->value, 6); @@ -361,28 +378,6 @@ xaw_update_one_value (widget_instance *instance, void xaw_destroy_instance (widget_instance *instance) { -#ifdef HAVE_XFT - if (instance->xft_data) - { - int i; - for (i = 0; i < instance->nr_xft_data; ++i) - { - if (instance->xft_data[i].xft_draw) - XftDrawDestroy (instance->xft_data[i].xft_draw); - if (instance->xft_data[i].p != None) - { - XtVaSetValues (instance->xft_data[i].widget, XtNbitmap, None, - NULL); - XFreePixmap (XtDisplay (instance->widget), - instance->xft_data[i].p); - } - } - if (instance->xft_data[0].xft_font) - XftFontClose (XtDisplay (instance->widget), - instance->xft_data[0].xft_font); - xfree (instance->xft_data); - } -#endif if (XtIsSubclass (instance->widget, dialogWidgetClass)) /* Need to destroy the Shell too. */ XtDestroyWidget (XtParent (instance->widget)); @@ -569,7 +564,6 @@ make_dialog (char* name, } } instance->xft_data = 0; - instance->nr_xft_data = 0; if (w) { XtResource rec[] = @@ -589,11 +583,13 @@ make_dialog (char* name, if (xft_font) { - instance->nr_xft_data = left_buttons + right_buttons + 1; - instance->xft_data = calloc (instance->nr_xft_data, + int nr_xft_data = left_buttons + right_buttons + 1; + instance->xft_data = calloc (nr_xft_data + 1, sizeof(*instance->xft_data)); fill_xft_data (&instance->xft_data[0], w, xft_font); + XtAddCallback (dialog, XtNdestroyCallback, destroy_xft_data, + instance->xft_data); } } diff --git a/lwlib/lwlib-int.h b/lwlib/lwlib-int.h index e21fa1f171..28b1fb9508 100644 --- a/lwlib/lwlib-int.h +++ b/lwlib/lwlib-int.h @@ -32,7 +32,6 @@ typedef struct _widget_instance Boolean pop_up_p; #ifdef HAVE_XFT struct widget_xft_data *xft_data; - int nr_xft_data; #endif struct _widget_info* info; struct _widget_instance* next; commit 6fa8d3c894062e7d3bde2d1ed35b40f2272e59f5 Author: Paul Eggert Date: Mon Apr 22 20:44:11 2019 -0700 Let plain ‘make’ work even not GNU Make * Makefile.in (top_distclean): Clean makefile as well as Makefile. * configure.ac: If not using plain ‘make’, create a makefile so that plain ‘make’ simply calls $(MAKE). diff --git a/Makefile.in b/Makefile.in index 53703638c4..6b99d24da4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -869,7 +869,7 @@ top_bootclean=\ top_distclean=\ ${top_bootclean}; \ rm -f config.status config.log~ \ - Makefile lib/gnulib.mk ${SUBDIR_MAKEFILES} + Makefile makefile lib/gnulib.mk ${SUBDIR_MAKEFILES} distclean_dirs = $(clean_dirs) leim lisp diff --git a/configure.ac b/configure.ac index 0ecb8c40e6..8b363c7fca 100644 --- a/configure.ac +++ b/configure.ac @@ -5814,4 +5814,12 @@ you can continue to support by using '$0 --with-pop'.]) esac fi -test "$MAKE" = make || AC_MSG_NOTICE([Now you can run '$MAKE'.]) +# Let plain 'make' work. +test "$MAKE" = make || test -f makefile || cat >makefile < Date: Mon Apr 22 20:02:20 2019 -0700 Revert Vinternal_interpreter_environment tweak Stefan Monnier pointed out examples like (funcall `(closure ,(let ((cycle (list nil))) (setcdr cycle cycle)) () a)), where the user can set Vinternal_interpreter_environment indirectly. * src/eval.c (Fsetq): Revert recent change, going back to Fassq. diff --git a/src/eval.c b/src/eval.c index fde63f1a21..3fd9a40a3a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -513,7 +513,7 @@ usage: (setq [SYM VAL]...) */) Lisp_Object lex_binding = ((!NILP (Vinternal_interpreter_environment) /* Mere optimization! */ && SYMBOLP (sym)) - ? assq_no_quit (sym, Vinternal_interpreter_environment) + ? Fassq (sym, Vinternal_interpreter_environment) : Qnil); if (!NILP (lex_binding)) XSETCDR (lex_binding, val); /* SYM is lexically bound. */ @@ -2162,7 +2162,7 @@ eval_sub (Lisp_Object form) already did that when let-binding the variable. */ Lisp_Object lex_binding = (!NILP (Vinternal_interpreter_environment) /* Mere optimization! */ - ? assq_no_quit (form, Vinternal_interpreter_environment) + ? Fassq (form, Vinternal_interpreter_environment) : Qnil); return !NILP (lex_binding) ? XCDR (lex_binding) : Fsymbol_value (form); } commit 27540be5c6265821d8197beeebb82113994c6b94 Author: Paul Eggert Date: Mon Apr 22 17:26:11 2019 -0700 Improve UBSan discussion in etc/DEBUG * etc/DEBUG: Improve -gdwarf-N documentation. Go into more detail about UndefinedBehaviorSanitizer. diff --git a/etc/DEBUG b/etc/DEBUG index 717553871a..836e820e4a 100644 --- a/etc/DEBUG +++ b/etc/DEBUG @@ -181,10 +181,10 @@ Good luck! ** When you are trying to analyze failed assertions or backtraces, it is essential to compile Emacs with flags suitable for debugging. -With GCC 4.8 or later, you can invoke 'make' with CFLAGS="-O0 -g3". -With older GCC, you can use CFLAGS="-O0 -g3 -gdwarf-4", replacing "4" -by the highest version of DWARF that your compiler supports; -with non-GCC compilers, "-O0 -g3" may be the best you can do. +Although CFLAGS="-O0 -g3" often suffices with modern compilers, +you may benefit further by using CFLAGS="-O0 -g3 -gdwarf-4", replacing +"4" by the highest version of DWARF that your compiler supports; +this is especially important for GCC versions older than 4.8. With GCC and higher optimization levels such as -O2, the -fno-omit-frame-pointer and -fno-crossjumping options are often essential. The latter prevents GCC from using the same abort call for @@ -917,13 +917,26 @@ setting the new-console option before running Emacs under GDB: ** Running Emacs with undefined-behavior sanitization -Building Emacs with undefined-behavior sanitization can help debug -integer overflow and other undefined behavior in C code. To use -UndefinedBehaviorSanitizer with GCC and similar compilers, append -'-fsanitize=undefined' to CFLAGS, either when running 'configure' or -running 'make'. For example: +Building Emacs with undefined-behavior sanitization can help find +several kinds of low-level problems in C code, including: - ./configure CFLAGS='-O0 -g3 -fsanitize=undefined' + * Out-of-bounds access of many (but not all) arrays. + * Signed integer overflow, e.g., (INT_MAX + 1). + * Integer shifts by a negative or wider-than-word value. + * Misaligned pointers and pointer overflow. + * Loading a bool or enum value that is out of range for its type. + * Passing NULL to or returning NULL from a function requiring nonnull. + * Passing a size larger than the corresponding array to memcmp etc. + * Passing invalid values to some builtin functions, e.g., __builtin_clz (0). + * Reaching __builtin_unreachable calls (in Emacs, 'eassume' failure). + +To use UndefinedBehaviorSanitizer with GCC and similar compilers, +append '-fsanitize=undefined' to CFLAGS, either when running +'configure' or running 'make'. When supported, you can also specify +'bound-strict' and 'float-cast-overflow'. For example: + + ./configure \ + CFLAGS='-O0 -g3 -fsanitize=undefined,bounds-strict,float-cast-overflow' You may need to append '-static-libubsan' to CFLAGS if your version of GCC is installed in an unusual location. @@ -940,9 +953,10 @@ program. ** Running Emacs with address sanitization Building Emacs with address sanitization can help debug memory-use -problems. To use AddressSanitizer with GCC and similar compilers, -append '-fsanitize=address' to CFLAGS, either when running 'configure' -or running 'make'. Configure, build and run Emacs with +problems, such as freeing the same object twice. To use +AddressSanitizer with GCC and similar compilers, append +'-fsanitize=address' to CFLAGS, either when running 'configure' or +running 'make'. Configure, build and run Emacs with ASAN_OPTIONS='detect_leaks=0' in the environment to suppress diagnostics of minor memory leaks in Emacs. For example: commit b8e7be28336ea02e899fbf4a67780e0528327d1a Author: Paul Eggert Date: Mon Apr 22 12:34:26 2019 -0700 Tweak Vinternal_interpreter_environment lookup * src/eval.c (Fsetq, eval_sub): Use assq_no_quit instead of Fassq for a list that cannot contain cycles or be that long. diff --git a/src/eval.c b/src/eval.c index 4693767ce7..fde63f1a21 100644 --- a/src/eval.c +++ b/src/eval.c @@ -501,7 +501,7 @@ usage: (setq [SYM VAL]...) */) for (EMACS_INT nargs = 0; CONSP (tail); nargs += 2) { - Lisp_Object sym = XCAR (tail), lex_binding; + Lisp_Object sym = XCAR (tail); tail = XCDR (tail); if (!CONSP (tail)) xsignal2 (Qwrong_number_of_arguments, Qsetq, make_fixnum (nargs + 1)); @@ -510,10 +510,12 @@ usage: (setq [SYM VAL]...) */) val = eval_sub (arg); /* Like for eval_sub, we do not check declared_special here since it's been done when let-binding. */ - if (!NILP (Vinternal_interpreter_environment) /* Mere optimization! */ - && SYMBOLP (sym) - && !NILP (lex_binding - = Fassq (sym, Vinternal_interpreter_environment))) + Lisp_Object lex_binding + = ((!NILP (Vinternal_interpreter_environment) /* Mere optimization! */ + && SYMBOLP (sym)) + ? assq_no_quit (sym, Vinternal_interpreter_environment) + : Qnil); + if (!NILP (lex_binding)) XSETCDR (lex_binding, val); /* SYM is lexically bound. */ else Fset (sym, val); /* SYM is dynamically bound. */ @@ -2159,9 +2161,9 @@ eval_sub (Lisp_Object form) We do not pay attention to the declared_special flag here, since we already did that when let-binding the variable. */ Lisp_Object lex_binding - = !NILP (Vinternal_interpreter_environment) /* Mere optimization! */ - ? Fassq (form, Vinternal_interpreter_environment) - : Qnil; + = (!NILP (Vinternal_interpreter_environment) /* Mere optimization! */ + ? assq_no_quit (form, Vinternal_interpreter_environment) + : Qnil); return !NILP (lex_binding) ? XCDR (lex_binding) : Fsymbol_value (form); } commit 8882419798bb9508fce23e6c4a85df7f9876dda8 Author: Paul Eggert Date: Mon Apr 22 12:25:40 2019 -0700 Improve wur coverage on older GCCs * src/conf_post.h (__has_attribute_warn_unused_result): New macro for compilers lacking __has_attribute. * src/systhread.h (__has_attribute): Remove ineffective define. (ATTRIBUTE_WARN_UNUSED_RESULT): Work better on GCC 3.4 thru 4. diff --git a/src/conf_post.h b/src/conf_post.h index 6ea2c7b664..7699d2c95b 100644 --- a/src/conf_post.h +++ b/src/conf_post.h @@ -78,6 +78,7 @@ typedef bool bool_bf; # define __has_attribute_no_address_safety_analysis false # define __has_attribute_no_sanitize_address GNUC_PREREQ (4, 8, 0) # define __has_attribute_no_sanitize_undefined GNUC_PREREQ (4, 9, 0) +# define __has_attribute_warn_unused_result GNUC_PREREQ (3, 4, 0) #endif /* Simulate __has_feature on compilers that lack it. It is used only diff --git a/src/systhread.h b/src/systhread.h index a1d2746721..8070bcde75 100644 --- a/src/systhread.h +++ b/src/systhread.h @@ -21,12 +21,8 @@ along with GNU Emacs. If not, see . */ #include -#ifndef __has_attribute -# define __has_attribute(a) false -#endif - -#if __has_attribute (__warn_unused_result__) -# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#if __has_attribute (warn_unused_result) +# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) #else # define ATTRIBUTE_WARN_UNUSED_RESULT #endif commit 4bf3c94939406de6610cc83476adaed789826623 Author: Paul Eggert Date: Mon Apr 22 11:40:13 2019 -0700 Go back to old way of checking json int range Although the lisp.h macros really need improvement, INTEGER_TO_INT is not the right way to go about it, as it causes conversion from intmax_t to uintmax_t and back again, which can cause a signal if the value is negative. * src/lisp.h (INTEGER_TO_INT, ranged_integer_to_int) (ranged_integer_to_uint): Remove, reverting recent changes to this file. * src/json.c (lisp_to_json): Revert to previous code, as the change messes up with uintmax_t<->intmax_t conversion. diff --git a/src/json.c b/src/json.c index 16500bce72..256d485eea 100644 --- a/src/json.c +++ b/src/json.c @@ -495,7 +495,14 @@ lisp_to_json (Lisp_Object lisp, struct json_configuration *conf) else if (EQ (lisp, Qt)) return json_check (json_true ()); else if (INTEGERP (lisp)) - return json_check (json_integer (INTEGER_TO_INT (lisp, json_int_t))); + { + intmax_t low = TYPE_MINIMUM (json_int_t); + intmax_t high = TYPE_MAXIMUM (json_int_t); + intmax_t value; + if (! (integer_to_intmax (lisp, &value) && low <= value && value <= high)) + args_out_of_range_3 (lisp, make_int (low), make_int (high)); + return json_check (json_integer (value)); + } else if (FLOATP (lisp)) return json_check (json_real (XFLOAT_DATA (lisp))); else if (STRINGP (lisp)) diff --git a/src/lisp.h b/src/lisp.h index ee5a8481ae..d803f16000 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2640,13 +2640,6 @@ make_uint (uintmax_t n) #define INT_TO_INTEGER(expr) \ (EXPR_SIGNED (expr) ? make_int (expr) : make_uint (expr)) -/* Return the integral value of NUM. If NUM is too big for TYPE, - signal an error. */ -#define INTEGER_TO_INT(num, type) \ - (TYPE_SIGNED (type) \ - ? ranged_integer_to_int ((num), TYPE_MINIMUM (type), TYPE_MAXIMUM (type)) \ - : ranged_integer_to_uint ((num), TYPE_MAXIMUM (type))) - /* Forwarding pointer to an int variable. This is allowed only in the value cell of a symbol, @@ -5023,26 +5016,6 @@ maybe_gc (void) garbage_collect (); } -INLINE intmax_t -ranged_integer_to_int (Lisp_Object num, intmax_t min, intmax_t max) -{ - CHECK_INTEGER (num); - intmax_t result; - if (!(integer_to_intmax (num, &result) && min <= result && result <= max)) - args_out_of_range_3 (num, make_int (min), make_int (max)); - return result; -} - -INLINE uintmax_t -ranged_integer_to_uint (Lisp_Object num, uintmax_t max) -{ - CHECK_INTEGER (num); - uintmax_t result; - if (!(integer_to_uintmax (num, &result) && result <= max)) - args_out_of_range_3 (num, make_fixed_natnum (0), make_uint (max)); - return result; -} - INLINE_HEADER_END #endif /* EMACS_LISP_H */ commit 981470e3590534a4d2947dfe5626cae832c6502d Author: Philipp Stephani Date: Mon Apr 22 18:58:51 2019 +0200 * src/lisp.h (INTEGER_TO_INT): Fix bug. diff --git a/src/lisp.h b/src/lisp.h index 8510ad7256..ee5a8481ae 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2645,7 +2645,7 @@ make_uint (uintmax_t n) #define INTEGER_TO_INT(num, type) \ (TYPE_SIGNED (type) \ ? ranged_integer_to_int ((num), TYPE_MINIMUM (type), TYPE_MAXIMUM (type)) \ - : ranged_integer_to_uint ((num), TYPE_MINIMUM (type))) + : ranged_integer_to_uint ((num), TYPE_MAXIMUM (type))) /* Forwarding pointer to an int variable. commit 11e75b031baad4305b2a6fd52dc43d11d65c7dc5 Author: Mattias Engdegård Date: Sat Apr 20 13:16:37 2019 +0200 Precise handling of filenotify `stopped' events * lisp/autorevert.el (auto-revert-notify-handler): When getting a `stopped' event, deal with it for the buffers it applies to, rather than for all buffers in auto-revert mode. diff --git a/lisp/autorevert.el b/lisp/autorevert.el index 6f2415a3ae..2d148d6095 100644 --- a/lisp/autorevert.el +++ b/lisp/autorevert.el @@ -594,19 +594,16 @@ no more reverts are possible until the next call of (if (eq action 'stopped) ;; File notification has stopped. Continue with polling. - (cl-dolist (buffer - (if global-auto-revert-mode - (buffer-list) auto-revert-buffer-list)) + (cl-dolist (buffer buffers) (with-current-buffer buffer - (when (and (equal descriptor auto-revert-notify-watch-descriptor) - (or - ;; A buffer associated with a file. - (and (stringp buffer-file-name) - (string-equal - (file-name-nondirectory file) - (file-name-nondirectory buffer-file-name))) - ;; A buffer w/o a file, like dired. - (null buffer-file-name))) + (when (or + ;; A buffer associated with a file. + (and (stringp buffer-file-name) + (string-equal + (file-name-nondirectory file) + (file-name-nondirectory buffer-file-name))) + ;; A buffer w/o a file, like dired. + (null buffer-file-name)) (auto-revert-notify-rm-watch)))) ;; Loop over all buffers, in order to find the intended one. commit f20c1ffd05aab43a14ade3c433216a6c6fbe4b24 Author: Mattias Engdegård Date: Mon Apr 22 18:04:00 2019 +0200 * autorevert.el (auto-revert-notify-rm-watch): Simplify. diff --git a/lisp/autorevert.el b/lisp/autorevert.el index 4fb865e8ad..6f2415a3ae 100644 --- a/lisp/autorevert.el +++ b/lisp/autorevert.el @@ -499,18 +499,16 @@ will use an up-to-date value of `auto-revert-interval'" (defun auto-revert-notify-rm-watch () "Disable file notification for current buffer's associated file." - (when auto-revert-notify-watch-descriptor - (maphash - (lambda (key value) - (when (equal key auto-revert-notify-watch-descriptor) - (setq value (delete (current-buffer) value)) - (if value - (puthash key value auto-revert-notify-watch-descriptor-hash-list) - (remhash key auto-revert-notify-watch-descriptor-hash-list) - (ignore-errors - (file-notify-rm-watch auto-revert-notify-watch-descriptor))))) - auto-revert-notify-watch-descriptor-hash-list) - (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch t)) + (let ((desc auto-revert-notify-watch-descriptor) + (table auto-revert-notify-watch-descriptor-hash-list)) + (when desc + (let ((buffers (delq (current-buffer) (gethash desc table)))) + (if buffers + (puthash desc buffers table) + (remhash desc table))) + (ignore-errors + (file-notify-rm-watch desc)) + (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch t))) (setq auto-revert-notify-watch-descriptor nil auto-revert-notify-modified-p nil)) commit 87d1dc19c933de522a6f4341701903b6418f3abe Author: Mattias Engdegård Date: Mon Apr 22 17:55:32 2019 +0200 Revert "Don't remove notify descriptor that is already gone" This reverts commit e9e807e9317ca7aa99a5dd220ee8586f8f4331bf, which is no longer necessary as `file-notify-rm-watch' has been made robust against reentry. diff --git a/lisp/autorevert.el b/lisp/autorevert.el index 1dc2f0eafd..4fb865e8ad 100644 --- a/lisp/autorevert.el +++ b/lisp/autorevert.el @@ -287,7 +287,7 @@ You should set this variable through Custom." (dolist (buf (buffer-list)) (with-current-buffer buf (when (symbol-value 'auto-revert-notify-watch-descriptor) - (auto-revert-notify-rm-watch t)))))) + (auto-revert-notify-rm-watch)))))) :initialize 'custom-initialize-default :version "24.4") @@ -371,7 +371,7 @@ without being changed in the part that is already in the buffer." 'kill-buffer-hook #'auto-revert-remove-current-buffer nil t)) - (when auto-revert-notify-watch-descriptor (auto-revert-notify-rm-watch t)) + (when auto-revert-notify-watch-descriptor (auto-revert-notify-rm-watch)) (auto-revert-remove-current-buffer)) (auto-revert-set-timer) (when auto-revert-mode @@ -480,7 +480,7 @@ specifies in the mode line." (dolist (buf (buffer-list)) (with-current-buffer buf (when auto-revert-notify-watch-descriptor - (auto-revert-notify-rm-watch t)))))) + (auto-revert-notify-rm-watch)))))) (defun auto-revert-set-timer () "Restart or cancel the timer used by Auto-Revert Mode. @@ -497,10 +497,8 @@ will use an up-to-date value of `auto-revert-interval'" auto-revert-interval 'auto-revert-buffers)))) -(defun auto-revert-notify-rm-watch (remove-descriptor) - "Disable file notification for current buffer's associated file. -If REMOVE-DESCRIPTOR is non-nil, remove the corresponding notification -descriptor; otherwise assume that it has already been removed." +(defun auto-revert-notify-rm-watch () + "Disable file notification for current buffer's associated file." (when auto-revert-notify-watch-descriptor (maphash (lambda (key value) @@ -509,19 +507,13 @@ descriptor; otherwise assume that it has already been removed." (if value (puthash key value auto-revert-notify-watch-descriptor-hash-list) (remhash key auto-revert-notify-watch-descriptor-hash-list) - (when remove-descriptor - (ignore-errors - (file-notify-rm-watch auto-revert-notify-watch-descriptor)))))) + (ignore-errors + (file-notify-rm-watch auto-revert-notify-watch-descriptor))))) auto-revert-notify-watch-descriptor-hash-list) - (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch-callback t)) + (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch t)) (setq auto-revert-notify-watch-descriptor nil auto-revert-notify-modified-p nil)) -(defun auto-revert-notify-rm-watch-callback () - "Disable file notification for current buffer's associated file, -and remove the notification descriptor." - (auto-revert-notify-rm-watch t)) - (defun auto-revert-notify-add-watch () "Enable file notification for current buffer's associated file." ;; We can assume that `auto-revert-notify-watch-descriptor' is nil. @@ -561,8 +553,7 @@ and remove the notification descriptor." (gethash auto-revert-notify-watch-descriptor auto-revert-notify-watch-descriptor-hash-list)) auto-revert-notify-watch-descriptor-hash-list) - (add-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch-callback - nil t))))) + (add-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch nil t))))) ;; If we have file notifications, we want to update the auto-revert buffers ;; immediately when a notification occurs. Since file updates can happen very @@ -618,9 +609,7 @@ no more reverts are possible until the next call of (file-name-nondirectory buffer-file-name))) ;; A buffer w/o a file, like dired. (null buffer-file-name))) - ;; Since we got a `stopped' event, the notification descriptor - ;; is already gone; don't try to remove it. - (auto-revert-notify-rm-watch nil)))) + (auto-revert-notify-rm-watch)))) ;; Loop over all buffers, in order to find the intended one. (cl-dolist (buffer buffers) commit c243aabfa8d280adf75024c8e6c0e68a7932f6cf Author: Mattias Engdegård Date: Sat Apr 20 10:19:52 2019 +0200 Make file-notify-rm-watch robust against reentry Allow file-notify callbacks to call `file-notify-rm-watch', harmlessly, after receiving a `stopped' event without triggering recursion. * lisp/filenotify.el (file-notify--watch): Note that `callback' can be nil. (file-notify--rm-descriptor): Set the `callback' field to nil before sending `stopped'. (file-notify-rm-watch): Don't do anything if the `callback' field is nil. diff --git a/lisp/filenotify.el b/lisp/filenotify.el index 3f9bb960a9..62dd1cd911 100644 --- a/lisp/filenotify.el +++ b/lisp/filenotify.el @@ -49,7 +49,7 @@ could use another implementation.") directory ;; Watched relative filename, nil if watching the directory. filename - ;; Function to propagate events to. + ;; Function to propagate events to, or nil if watch is being removed. callback) (defun file-notify--watch-absolute-filename (watch) @@ -72,12 +72,15 @@ struct.") DESCRIPTOR should be an object returned by `file-notify-add-watch'. If it is registered in `file-notify-descriptors', a stopped event is sent." (when-let* ((watch (gethash descriptor file-notify-descriptors))) - ;; Send `stopped' event. - (unwind-protect - (funcall - (file-notify--watch-callback watch) - `(,descriptor stopped ,(file-notify--watch-absolute-filename watch))) - (remhash descriptor file-notify-descriptors)))) + (let ((callback (file-notify--watch-callback watch))) + ;; Make sure this is the last time the callback is invoked. + (setf (file-notify--watch-callback watch) nil) + ;; Send `stopped' event. + (unwind-protect + (funcall + callback + `(,descriptor stopped ,(file-notify--watch-absolute-filename watch))) + (remhash descriptor file-notify-descriptors))))) ;; This function is used by `inotify', `kqueue', `gfilenotify' and ;; `w32notify' events. @@ -381,25 +384,27 @@ FILE is the name of the file whose event is being reported." "Remove an existing watch specified by its DESCRIPTOR. DESCRIPTOR should be an object returned by `file-notify-add-watch'." (when-let* ((watch (gethash descriptor file-notify-descriptors))) - (let ((handler (find-file-name-handler - (file-notify--watch-directory watch) - 'file-notify-rm-watch))) - (condition-case nil - (if handler - ;; A file name handler could exist even if there is no - ;; local file notification support. - (funcall handler 'file-notify-rm-watch descriptor) - - (funcall - (cond - ((eq file-notify--library 'inotify) 'inotify-rm-watch) - ((eq file-notify--library 'kqueue) 'kqueue-rm-watch) - ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch) - ((eq file-notify--library 'w32notify) 'w32notify-rm-watch)) - descriptor)) - (file-notify-error nil))) - ;; Modify `file-notify-descriptors'. - (file-notify--rm-descriptor descriptor))) + ;; If we are called from a `stopped' event, do nothing. + (when (file-notify--watch-callback watch) + (let ((handler (find-file-name-handler + (file-notify--watch-directory watch) + 'file-notify-rm-watch))) + (condition-case nil + (if handler + ;; A file name handler could exist even if there is no + ;; local file notification support. + (funcall handler 'file-notify-rm-watch descriptor) + + (funcall + (cond + ((eq file-notify--library 'inotify) 'inotify-rm-watch) + ((eq file-notify--library 'kqueue) 'kqueue-rm-watch) + ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch) + ((eq file-notify--library 'w32notify) 'w32notify-rm-watch)) + descriptor)) + (file-notify-error nil))) + ;; Modify `file-notify-descriptors' and send a `stopped' event. + (file-notify--rm-descriptor descriptor)))) (defun file-notify-valid-p (descriptor) "Check a watch specified by its DESCRIPTOR. commit 4e2ea400cbd78fa791fb897938a6dcb099401a25 Author: Philipp Stephani Date: Mon Apr 22 17:29:06 2019 +0200 Introduce a helper macro to convert a Lisp integer to a C integer. This is similar to CONS_TO_INTEGER. The inverse (INT_TO_INTEGER) already exists. * src/lisp.h (INTEGER_TO_INT): New macro. (ranged_integer_to_int, ranged_integer_to_uint): New functions. * src/json.c (lisp_to_json): Use helper macro. diff --git a/src/json.c b/src/json.c index 928825e034..16500bce72 100644 --- a/src/json.c +++ b/src/json.c @@ -495,14 +495,7 @@ lisp_to_json (Lisp_Object lisp, struct json_configuration *conf) else if (EQ (lisp, Qt)) return json_check (json_true ()); else if (INTEGERP (lisp)) - { - intmax_t low = TYPE_MINIMUM (json_int_t); - intmax_t high = TYPE_MAXIMUM (json_int_t); - intmax_t value; - if (! integer_to_intmax (lisp, &value) || value < low || high < value) - args_out_of_range_3 (lisp, make_int (low), make_int (high)); - return json_check (json_integer (value)); - } + return json_check (json_integer (INTEGER_TO_INT (lisp, json_int_t))); else if (FLOATP (lisp)) return json_check (json_real (XFLOAT_DATA (lisp))); else if (STRINGP (lisp)) diff --git a/src/lisp.h b/src/lisp.h index d803f16000..8510ad7256 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2640,6 +2640,13 @@ make_uint (uintmax_t n) #define INT_TO_INTEGER(expr) \ (EXPR_SIGNED (expr) ? make_int (expr) : make_uint (expr)) +/* Return the integral value of NUM. If NUM is too big for TYPE, + signal an error. */ +#define INTEGER_TO_INT(num, type) \ + (TYPE_SIGNED (type) \ + ? ranged_integer_to_int ((num), TYPE_MINIMUM (type), TYPE_MAXIMUM (type)) \ + : ranged_integer_to_uint ((num), TYPE_MINIMUM (type))) + /* Forwarding pointer to an int variable. This is allowed only in the value cell of a symbol, @@ -5016,6 +5023,26 @@ maybe_gc (void) garbage_collect (); } +INLINE intmax_t +ranged_integer_to_int (Lisp_Object num, intmax_t min, intmax_t max) +{ + CHECK_INTEGER (num); + intmax_t result; + if (!(integer_to_intmax (num, &result) && min <= result && result <= max)) + args_out_of_range_3 (num, make_int (min), make_int (max)); + return result; +} + +INLINE uintmax_t +ranged_integer_to_uint (Lisp_Object num, uintmax_t max) +{ + CHECK_INTEGER (num); + uintmax_t result; + if (!(integer_to_uintmax (num, &result) && result <= max)) + args_out_of_range_3 (num, make_fixed_natnum (0), make_uint (max)); + return result; +} + INLINE_HEADER_END #endif /* EMACS_LISP_H */ commit 3b4e312cfe1e0b185fea58bc35fa951a8389c144 Author: Philipp Stephani Date: Sun Apr 21 18:09:38 2019 +0200 Improve documentation around standard error pipes (Bug#35328). * doc/lispref/processes.texi (Asynchronous Processes): Document existence and properties of the standard error process. (Accepting Output): Document that one has to accept output from the standard error process separately. diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 7eb136af5f..c08b14c72c 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -701,6 +701,19 @@ created with @code{make-pipe-process}, described below. If @var{stderr} is @code{nil}, standard error is mixed with standard output, and both are sent to @var{buffer} or @var{filter}. +@cindex standard error process +If @var{stderr} is a buffer, Emacs will create a pipe process, the +@dfn{standard error process}. This process will have the default +filter (@pxref{Filter Functions}), sentinel (@pxref{Sentinels}), and +coding systems (@pxref{Default Coding Systems}). On the other hand, +it will use @var{query-flag} as its query-on-exit flag (@pxref{Query +Before Exit}). It will be associated with the @var{stderr} buffer +(@pxref{Process Buffers}) and send its output (which is the standard +error of the main process) there. + +If @var{stderr} is a pipe process, Emacs will use it as standard error +process for the new process. + @item :file-handler @var{file-handler} If @var{file-handler} is non-@code{nil}, then look for a file name handler for the current buffer's @code{default-directory}, and invoke @@ -1882,6 +1895,19 @@ like this: (while (accept-process-output process)) @end example +If you have passed a non-@code{nil} @var{stderr} to +@code{make-process}, it will have a standard error process. +@xref{Asynchronous Processes}. In that case, waiting for process +output from the main process doesn't wait for output from the standard +error process. To make sure you have received both all of standard +output and all of standard error from a process, use the following +code: + +@example +(while (accept-process-output process)) +(while (accept-process-output stderr-process)) +@end example + @node Processes and Threads @subsection Processes and Threads @cindex processes, threads commit f9659e648cd06a9322b501168b1af8ede7d1ae16 Author: Philipp Stephani Date: Mon Apr 22 15:43:52 2019 +0200 Module API: Don’t require null-terminated strings in make_string. * emacs-module.c (module_make_string): Use make_unibyte_string, which doesn’t require its argument to be null-terminated. Since it always returns a heap-allocated string, we don’t have to copy it any more while decoding. (module_decode): New helper function. diff --git a/src/emacs-module.c b/src/emacs-module.c index 8fd2a87cc2..20dcff2b67 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -212,6 +212,7 @@ static void module_reset_handlerlist (struct handler **); static bool value_storage_contains_p (const struct emacs_value_storage *, emacs_value, ptrdiff_t *); static Lisp_Object module_encode (Lisp_Object); +static Lisp_Object module_decode (Lisp_Object); static Lisp_Object module_decode_copy (Lisp_Object); static bool module_assertions = false; @@ -629,10 +630,8 @@ module_make_string (emacs_env *env, const char *str, ptrdiff_t length) MODULE_FUNCTION_BEGIN (NULL); if (! (0 <= length && length <= STRING_BYTES_BOUND)) overflow_error (); - /* FIXME: AUTO_STRING_WITH_LEN requires STR to be NUL-terminated, - but we shouldn't require that. */ - AUTO_STRING_WITH_LEN (lstr, str, length); - return lisp_to_value (env, module_decode_copy (lstr)); + Lisp_Object lstr = make_unibyte_string (str, length); + return lisp_to_value (env, module_decode (lstr)); } static emacs_value @@ -946,6 +945,12 @@ module_encode (Lisp_Object string) return code_convert_string (string, Qutf_8_unix, Qt, true, true, true); } +static Lisp_Object +module_decode (Lisp_Object string) +{ + return code_convert_string (string, Qutf_8_unix, Qt, false, true, true); +} + static Lisp_Object module_decode_copy (Lisp_Object string) { commit ca3ad9746da5ced05e8fd692731ffe4dcb52d7e8 Author: Philipp Stephani Date: Mon Apr 22 15:39:39 2019 +0200 Use utf-8-unix for coding system conversions in the module API. Factor out conversions into helper functions to provide a simpler interface. * src/emacs-module.c (module_encode, module_decode_copy): New helper functions. (module_make_function, module_copy_string_contents) (module_make_string): Use them. diff --git a/src/emacs-module.c b/src/emacs-module.c index 68bee70626..8fd2a87cc2 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -211,6 +211,8 @@ static void module_out_of_memory (emacs_env *); static void module_reset_handlerlist (struct handler **); static bool value_storage_contains_p (const struct emacs_value_storage *, emacs_value, ptrdiff_t *); +static Lisp_Object module_encode (Lisp_Object); +static Lisp_Object module_decode_copy (Lisp_Object); static bool module_assertions = false; @@ -496,8 +498,7 @@ module_make_function (emacs_env *env, ptrdiff_t min_arity, ptrdiff_t max_arity, if (documentation) { AUTO_STRING (unibyte_doc, documentation); - function->documentation = - code_convert_string_norecord (unibyte_doc, Qutf_8, false); + function->documentation = module_decode_copy (unibyte_doc); } Lisp_Object result; @@ -600,7 +601,7 @@ module_copy_string_contents (emacs_env *env, emacs_value value, char *buffer, Lisp_Object lisp_str = value_to_lisp (value); CHECK_STRING (lisp_str); - Lisp_Object lisp_str_utf8 = ENCODE_UTF_8 (lisp_str); + Lisp_Object lisp_str_utf8 = module_encode (lisp_str); ptrdiff_t raw_size = SBYTES (lisp_str_utf8); ptrdiff_t required_buf_size = raw_size + 1; @@ -631,8 +632,7 @@ module_make_string (emacs_env *env, const char *str, ptrdiff_t length) /* FIXME: AUTO_STRING_WITH_LEN requires STR to be NUL-terminated, but we shouldn't require that. */ AUTO_STRING_WITH_LEN (lstr, str, length); - return lisp_to_value (env, - code_convert_string_norecord (lstr, Qutf_8, false)); + return lisp_to_value (env, module_decode_copy (lstr)); } static emacs_value @@ -940,6 +940,18 @@ module_out_of_memory (emacs_env *env) XCDR (Vmemory_signal_data)); } +static Lisp_Object +module_encode (Lisp_Object string) +{ + return code_convert_string (string, Qutf_8_unix, Qt, true, true, true); +} + +static Lisp_Object +module_decode_copy (Lisp_Object string) +{ + return code_convert_string (string, Qutf_8_unix, Qt, false, false, true); +} + /* Value conversion. */ commit 4430a9b54fca266e48d0eb8b72d83706910f10b8 Author: Basil L. Contovounesios Date: Wed Apr 17 16:34:47 2019 +0100 Improve pure and side-effect-free docs For discussion, see thread starting at: https://lists.gnu.org/archive/html/emacs-devel/2019-04/msg00316.html * doc/lispref/customize.texi (Composite Types): Do not overspecify :match-alternatives predicates. * doc/lispref/eval.texi (Intro Eval): Anchor definition of "side effect" for cross-referencing... * doc/lispref/functions.texi (What Is a Function): ...from here. Define what a pure function is. * doc/lispref/internals.texi (Writing Emacs Primitives): Describe currently preferred approach to marking primitives as pure and side-effect-free. * doc/lispref/symbols.texi (Standard Properties): Expand description of pure and side-effect-free properties. diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi index f71dedfd8b..02eefe0f58 100644 --- a/doc/lispref/customize.texi +++ b/doc/lispref/customize.texi @@ -950,10 +950,10 @@ possibilities: @itemize @bullet @item -A predicate---that is, a function of one argument that has no side -effects, and returns either @code{nil} or non-@code{nil} according to -the argument. Using a predicate in the list says that objects for which -the predicate returns non-@code{nil} are acceptable. +A predicate---that is, a function of one argument that returns either +@code{nil} or non-@code{nil} according to the argument. Using a +predicate in the list says that objects for which the predicate +returns non-@code{nil} are acceptable. @item A quoted constant---that is, @code{'@var{object}}. This sort of element diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index db42dfb637..39c5a1ec50 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -87,6 +87,7 @@ also temporarily alter the environment by binding variables (@pxref{Local Variables}). @cindex side effect +@anchor{Definition of side effect} Evaluating a form may also make changes that persist; these changes are called @dfn{side effects}. An example of a form that produces a side effect is @code{(setq foo 1)}. diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 222f863c98..97f7fb9f79 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -38,11 +38,16 @@ define them. @cindex return value @cindex value of function @cindex argument +@cindex pure function In a general sense, a function is a rule for carrying out a computation given input values called @dfn{arguments}. The result of the computation is called the @dfn{value} or @dfn{return value} of the function. The computation can also have side effects, such as lasting -changes in the values of variables or the contents of data structures. +changes in the values of variables or the contents of data structures +(@pxref{Definition of side effect}). A @dfn{pure function} is a +function which, in addition to having no side effects, always returns +the same value for the same combination of arguments, regardless of +external factors such as machine type or system state. In most computer languages, every function has a name. But in Lisp, a function in the strictest sense has no name: it is an object which diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index fc5ce594e6..25892d4b57 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -1031,10 +1031,9 @@ number of arguments. They work by calling @code{Ffuncall}. @file{lisp.h} contains the definitions for some important macros and functions. - If you define a function which is side-effect free, update the code -in @file{byte-opt.el} that binds @code{side-effect-free-fns} and -@code{side-effect-and-error-free-fns} so that the compiler optimizer -knows about it. + If you define a function which is side-effect free or pure, give it +a non-@code{nil} @code{side-effect-free} or @code{pure} property, +respectively (@pxref{Standard Properties}). @node Writing Dynamic Modules @section Writing Dynamically-Loaded Modules diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi index a214a2d3fd..5d71fb39a2 100644 --- a/doc/lispref/symbols.texi +++ b/doc/lispref/symbols.texi @@ -558,9 +558,12 @@ deleted from the local value of a hook variable when changing major modes. @xref{Setting Hooks}. @item pure +@cindex @code{pure} property If the value is non-@code{nil}, the named function is considered to be -side-effect free. Calls with constant arguments can be evaluated at -compile time. This may shift run time errors to compile time. +pure (@pxref{What Is a Function}). Calls with constant arguments can +be evaluated at compile time. This may shift run time errors to +compile time. Not to be confused with pure storage (@pxref{Pure +Storage}). @item risky-local-variable If the value is non-@code{nil}, the named variable is considered risky @@ -579,9 +582,13 @@ The value specifies a function for determining safe file-local values for the named variable. @xref{File Local Variables}. @item side-effect-free +@cindex @code{side-effect-free} property A non-@code{nil} value indicates that the named function is free of -side-effects, for determining function safety (@pxref{Function -Safety}) as well as for byte compiler optimizations. Do not set it. +side effects (@pxref{What Is a Function}), so the byte compiler may +ignore a call whose value is unused. If the property's value is +@code{error-free}, the byte compiler may even delete such unused +calls. In addition to byte compiler optimizations, this property is +also used for determining function safety (@pxref{Function Safety}). @item variable-documentation If non-@code{nil}, this specifies the named variable's documentation commit a2a51b4e94d3e058a71815cb309a21b707c3473b Author: Philipp Stephani Date: Mon Apr 22 11:36:59 2019 +0200 Refactoring: Inline a few macros. Now that CATCHER_ALL catches signals as well, we can simplify MODULE_HANDLE_NONLOCAL_EXIT a bit. * src/emacs-module.c (MODULE_SETJMP, MODULE_SETJMP_1): Remove. (MODULE_HANDLE_NONLOCAL_EXIT): Inline MODULE_SETJMP and MODULE_SETJMP_1. diff --git a/src/emacs-module.c b/src/emacs-module.c index 2f60ef1f1f..68bee70626 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -224,26 +224,19 @@ static bool module_assertions = false; not prepared for long jumps (e.g., the behavior in C++ is undefined if objects with nontrivial destructors would be skipped). Therefore, catch all non-local exits. There are two kinds of - non-local exits: `signal' and `throw'. The macros in this section - can be used to catch both. Use macros to avoid additional variants + non-local exits: `signal' and `throw'. The macro in this section + can be used to catch both. Use a macro to avoid additional variants of `internal_condition_case' etc., and to avoid worrying about passing information to the handler functions. */ +#if !__has_attribute (cleanup) + #error "__attribute__ ((cleanup)) not supported by this compiler; try GCC" +#endif + /* Place this macro at the beginning of a function returning a number or a pointer to handle non-local exits. The function must have an ENV parameter. The function will return the specified value if a signal or throw is caught. */ -#define MODULE_HANDLE_NONLOCAL_EXIT(retval) \ - MODULE_SETJMP (CATCHER_ALL, module_handle_nonlocal_exit, retval) - -#define MODULE_SETJMP(handlertype, handlerfunc, retval) \ - MODULE_SETJMP_1 (handlertype, handlerfunc, retval, \ - internal_handler_##handlertype, \ - internal_cleanup_##handlertype) - -#if !__has_attribute (cleanup) - #error "__attribute__ ((cleanup)) not supported by this compiler; try GCC" -#endif /* It is very important that pushing the handler doesn't itself raise a signal. Install the cleanup only after the handler has been @@ -253,24 +246,28 @@ static bool module_assertions = false; The do-while forces uses of the macro to be followed by a semicolon. This macro cannot enclose its entire body inside a do-while, as the code after the macro may longjmp back into the macro, which means - its local variable C must stay live in later code. */ + its local variable INTERNAL_CLEANUP must stay live in later code. */ -/* TODO: Make backtraces work if this macros is used. */ +/* TODO: Make backtraces work if this macro is used. */ -#define MODULE_SETJMP_1(handlertype, handlerfunc, retval, c0, c) \ +#define MODULE_HANDLE_NONLOCAL_EXIT(retval) \ if (module_non_local_exit_check (env) != emacs_funcall_exit_return) \ return retval; \ - struct handler *c0 = push_handler_nosignal (Qt, handlertype); \ - if (!c0) \ + struct handler *internal_handler = \ + push_handler_nosignal (Qt, CATCHER_ALL); \ + if (!internal_handler) \ { \ module_out_of_memory (env); \ return retval; \ } \ - struct handler *c __attribute__ ((cleanup (module_reset_handlerlist))) \ - = c0; \ - if (sys_setjmp (c->jmp)) \ + struct handler *internal_cleanup \ + __attribute__ ((cleanup (module_reset_handlerlist))) \ + = internal_handler; \ + if (sys_setjmp (internal_cleanup->jmp)) \ { \ - (handlerfunc) (env, c->nonlocal_exit, c->val); \ + module_handle_nonlocal_exit (env, \ + internal_cleanup->nonlocal_exit, \ + internal_cleanup->val); \ return retval; \ } \ do { } while (false)