commit efa750e68466fb1bab03028701350a745e0504b6 (HEAD, refs/remotes/origin/master) Author: Paul Eggert Date: Sat Jun 9 18:59:25 2018 -0700 Simplify read_key_sequence * src/keyboard.c (READ_KEY_ELTS): New constant. (keyremap_step, read_key_sequence): Omit BUFSIZE arg, since it's always READ_KEY_ELTS. All callers changed. (grow_bool_vector): Remove; no longer needed. (read_key_sequence): Use a bool array instead of a Lisp bool vector, since it's small and this puts less pressure on the GC. diff --git a/src/keyboard.c b/src/keyboard.c index c92684d3a3..e6b5cf7998 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1251,7 +1251,8 @@ some_mouse_moved (void) /* This is the actual command reading loop, sans error-handling encapsulation. */ -static int read_key_sequence (Lisp_Object *, int, Lisp_Object, +enum { READ_KEY_ELTS = 30 }; +static int read_key_sequence (Lisp_Object *, Lisp_Object, bool, bool, bool, bool); static void adjust_point_for_property (ptrdiff_t, bool); @@ -1299,11 +1300,9 @@ command_loop_1 (void) if (!CONSP (last_command_event)) kset_last_repeatable_command (current_kboard, Vreal_this_command); - while (1) + while (true) { Lisp_Object cmd; - Lisp_Object keybuf[30]; - int i; if (! FRAME_LIVE_P (XFRAME (selected_frame))) Fkill_emacs (Qnil); @@ -1367,8 +1366,8 @@ command_loop_1 (void) /* Read next key sequence; i gets its length. */ raw_keybuf_count = 0; - i = read_key_sequence (keybuf, ARRAYELTS (keybuf), - Qnil, 0, 1, 1, 0); + Lisp_Object keybuf[READ_KEY_ELTS]; + int i = read_key_sequence (keybuf, Qnil, false, true, true, false); /* A filter may have run while we were reading the input. */ if (! FRAME_LIVE_P (XFRAME (selected_frame))) @@ -1604,16 +1603,14 @@ command_loop_1 (void) Lisp_Object read_menu_command (void) { - Lisp_Object keybuf[30]; ptrdiff_t count = SPECPDL_INDEX (); - int i; /* We don't want to echo the keystrokes while navigating the menus. */ specbind (Qecho_keystrokes, make_number (0)); - i = read_key_sequence (keybuf, ARRAYELTS (keybuf), - Qnil, 0, 1, 1, 1); + Lisp_Object keybuf[READ_KEY_ELTS]; + int i = read_key_sequence (keybuf, Qnil, false, true, true, true); unbind_to (count, Qnil); @@ -8778,8 +8775,7 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, /* Do one step of the key remapping used for function-key-map and key-translation-map: - KEYBUF is the buffer holding the input events. - BUFSIZE is its maximum size. + KEYBUF is the READ_KEY_ELTS-size buffer holding the input events. FKEY is a pointer to the keyremap structure to use. INPUT is the index of the last element in KEYBUF. DOIT if true says that the remapping can actually take place. @@ -8789,7 +8785,7 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, Return true if the remapping actually took place. */ static bool -keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey, +keyremap_step (Lisp_Object *keybuf, volatile keyremap *fkey, int input, bool doit, int *diff, Lisp_Object prompt) { Lisp_Object next, key; @@ -8811,7 +8807,7 @@ keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey, *diff = len - (fkey->end - fkey->start); - if (bufsize - input <= *diff) + if (READ_KEY_ELTS - input <= *diff) error ("Key sequence too long"); /* Shift the keys that follow fkey->end. */ @@ -8858,33 +8854,8 @@ void init_raw_keybuf_count (void) raw_keybuf_count = 0; } -/* Grow a vector to fit. - - On entry, *VECTOR is nil or a bool vector. Upon return, *VECTOR - contains a bool vector of size at least NEEDED_LENGTH, with any new - values to false. Return the new value of *VECTOR. */ -static Lisp_Object -grow_bool_vector (Lisp_Object *vector, int needed_length) -{ - EMACS_INT old_length = NILP (*vector) ? 0 : bool_vector_size (*vector); - if (NILP (*vector) || old_length < needed_length) - { - EMACS_INT new_length = old_length ? old_length : 64; - while (new_length < needed_length) - new_length *= 2; - Lisp_Object new_vector = - Fmake_bool_vector (make_number (needed_length), Qnil); - if (old_length) - memcpy (bool_vector_data (new_vector), - bool_vector_data (*vector), - bool_vector_bytes (old_length)); - *vector = new_vector; - } - return *vector; -} - /* Read a sequence of keys that ends with a non prefix character, - storing it in KEYBUF, a buffer of size BUFSIZE. + storing it in KEYBUF, a buffer of size READ_KEY_ELTS. Prompt with PROMPT. Return the length of the key sequence stored. Return -1 if the user rejected a command menu. @@ -8924,7 +8895,7 @@ grow_bool_vector (Lisp_Object *vector, int needed_length) from the selected window's buffer. */ static int -read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, +read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt, bool dont_downcase_last, bool can_return_switch_frame, bool fix_current_buffer, bool prevent_redisplay) { @@ -8959,10 +8930,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, reading characters from the keyboard. */ int mock_input = 0; - /* This bool vector remembers whether each event in the mocked input - came from a mouse menu. We ordinarily leave it nil and create it - the first time we remember a mouse event. */ - Lisp_Object used_mouse_menu_history = Qnil; + /* Whether each event in the mocked input came from a mouse menu. */ + bool used_mouse_menu_history[READ_KEY_ELTS] = {0}; /* Distinguish first time through from replay with mock_input == 0. */ bool is_replay = false; @@ -9057,7 +9026,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, replay_sequence: starting_buffer = current_buffer; - first_unbound = bufsize + 1; + first_unbound = READ_KEY_ELTS + 1; Lisp_Object first_event = mock_input > 0 ? keybuf[0] : Qnil; Lisp_Object second_event = mock_input > 1 ? keybuf[1] : Qnil; @@ -9139,7 +9108,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, goto replay_sequence; } - if (t >= bufsize) + if (t >= READ_KEY_ELTS) error ("Key sequence too long"); if (INTERACTIVE) @@ -9170,9 +9139,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, current_kboard->immediate_echo = false; echo_now (); } - used_mouse_menu = !NILP (used_mouse_menu_history) && - t < bool_vector_size (used_mouse_menu_history) && - bool_vector_bitref (used_mouse_menu_history, t); + used_mouse_menu = used_mouse_menu_history[t]; } /* If not, we should actually read a character. */ @@ -9186,10 +9153,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, key = read_char (prevent_redisplay ? -2 : NILP (prompt), current_binding, last_nonmenu_event, &used_mouse_menu, NULL); - if (used_mouse_menu || !NILP (used_mouse_menu_history)) - bool_vector_set ( - grow_bool_vector (&used_mouse_menu_history, t + 1), - t, used_mouse_menu); + used_mouse_menu_history[t] = used_mouse_menu; if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */ /* When switching to a new tty (with a new keyboard), read_char returns the new buffer, rather than -2 @@ -9417,7 +9381,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, && (NILP (fake_prefixed_keys) || NILP (Fmemq (key, fake_prefixed_keys)))) { - if (bufsize - t <= 1) + if (READ_KEY_ELTS - t <= 1) error ("Key sequence too long"); keybuf[t] = posn; @@ -9443,7 +9407,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, insert the dummy prefix event `menu-bar'. */ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) { - if (bufsize - t <= 1) + if (READ_KEY_ELTS - t <= 1) error ("Key sequence too long"); keybuf[t] = posn; keybuf[t + 1] = key; @@ -9646,8 +9610,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, bool done; int diff; - done = keyremap_step (keybuf, bufsize, &indec, max (t, mock_input), - 1, &diff, prompt); + done = keyremap_step (keybuf, &indec, max (t, mock_input), + true, &diff, prompt); if (done) { mock_input = diff + max (t, mock_input); @@ -9677,13 +9641,13 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, bool done; int diff; - done = keyremap_step (keybuf, bufsize, &fkey, + done = keyremap_step (keybuf, &fkey, max (t, mock_input), /* If there's a binding (i.e. first_binding >= nmaps) we don't want to apply this function-key-mapping. */ - fkey.end + 1 == t - && (test_undefined (current_binding)), + (fkey.end + 1 == t + && test_undefined (current_binding)), &diff, prompt); if (done) { @@ -9703,8 +9667,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, bool done; int diff; - done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input), - 1, &diff, prompt); + done = keyremap_step (keybuf, &keytran, max (t, mock_input), + true, &diff, prompt); if (done) { mock_input = diff + max (t, mock_input); @@ -9857,8 +9821,6 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop, bool allow_string) { - Lisp_Object keybuf[30]; - int i; ptrdiff_t count = SPECPDL_INDEX (); if (!NILP (prompt)) @@ -9882,9 +9844,9 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo, #endif raw_keybuf_count = 0; - i = read_key_sequence (keybuf, ARRAYELTS (keybuf), - prompt, ! NILP (dont_downcase_last), - ! NILP (can_return_switch_frame), 0, 0); + Lisp_Object keybuf[READ_KEY_ELTS]; + int i = read_key_sequence (keybuf, prompt, ! NILP (dont_downcase_last), + ! NILP (can_return_switch_frame), false, false); #if 0 /* The following is fine for code reading a key sequence and then proceeding with a lengthy computation, but it's not good commit cace203da108da4d281a99953a6fc71a18cde029 Author: Daniel Colascione Date: Sat Jun 9 18:12:15 2018 -0700 Unbreak echoing * src/keyboard.c (read_key_sequence): Don't echo_truncate the first time. diff --git a/src/keyboard.c b/src/keyboard.c index bd9292c265..c92684d3a3 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -8964,6 +8964,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, the first time we remember a mouse event. */ Lisp_Object used_mouse_menu_history = Qnil; + /* Distinguish first time through from replay with mock_input == 0. */ + bool is_replay = false; + /* If the sequence is unbound in submaps[], then keybuf[fkey.start..fkey.end-1] is a prefix in Vfunction_key_map, and fkey.map is its binding. @@ -9072,8 +9075,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* These are no-ops the first time through, but if we restart, they revert the echo area and this_command_keys to their original state. */ this_command_key_count = keys_start; - if (INTERACTIVE) + if (INTERACTIVE && is_replay) echo_truncate (echo_start); + is_replay = true; /* If the best binding for the current key sequence is a keymap, or we may be looking at a function key's escape sequence, keep on commit 3e3e23fb88fdc19e859c0aa2ab51b86afd323c71 Author: Paul Eggert Date: Sat Jun 9 17:56:29 2018 -0700 Fix pointer misuse in JSON parser * src/json.c (lisp_to_json_toplevel_1): Fix pointer misuse not caught by C type checking (json_t ** converted to void * where the program expected json_t *). Bug caught on Fedora 28 x86-64 via './configure CFLAGS="-g3 -O2 -fsanitize=address" CANNOT_DUMP=yes'. Avoid similar problems in the future by rewriting to use json_t * instead of json_t **. diff --git a/src/json.c b/src/json.c index afb81587a4..c28e14d63c 100644 --- a/src/json.c +++ b/src/json.c @@ -327,36 +327,35 @@ json_check_utf8 (Lisp_Object string) static json_t *lisp_to_json (Lisp_Object); -/* Convert a Lisp object to a toplevel JSON object (array or object). - This returns Lisp_Object so we can use unbind_to. The return value - is always nil. */ +/* Convert a Lisp object to a toplevel JSON object (array or object). */ -static _GL_ARG_NONNULL ((2)) Lisp_Object -lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) +static json_t * +lisp_to_json_toplevel_1 (Lisp_Object lisp) { + json_t *json; + ptrdiff_t count; + if (VECTORP (lisp)) { ptrdiff_t size = ASIZE (lisp); - *json = json_check (json_array ()); - ptrdiff_t count = SPECPDL_INDEX (); + json = json_check (json_array ()); + count = SPECPDL_INDEX (); record_unwind_protect_ptr (json_release_object, json); for (ptrdiff_t i = 0; i < size; ++i) { int status - = json_array_append_new (*json, lisp_to_json (AREF (lisp, i))); + = json_array_append_new (json, lisp_to_json (AREF (lisp, i))); if (status == -1) json_out_of_memory (); } - eassert (json_array_size (*json) == size); - clear_unwind_protect (count); - return unbind_to (count, Qnil); + eassert (json_array_size (json) == size); } else if (HASH_TABLE_P (lisp)) { struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); - *json = json_check (json_object ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, *json); + json = json_check (json_object ()); + count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, json); for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) if (!NILP (HASH_HASH (h, i))) { @@ -367,9 +366,9 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) const char *key_str = SSDATA (key); /* Reject duplicate keys. These are possible if the hash table test is not `equal'. */ - if (json_object_get (*json, key_str) != NULL) + if (json_object_get (json, key_str) != NULL) wrong_type_argument (Qjson_value_p, lisp); - int status = json_object_set_new (*json, key_str, + int status = json_object_set_new (json, key_str, lisp_to_json (HASH_VALUE (h, i))); if (status == -1) { @@ -379,20 +378,15 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) json_out_of_memory (); } } - clear_unwind_protect (count); - return unbind_to (count, Qnil); } else if (NILP (lisp)) - { - *json = json_check (json_object ()); - return Qnil; - } + return json_check (json_object ()); else if (CONSP (lisp)) { Lisp_Object tail = lisp; - *json = json_check (json_object ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, *json); + json = json_check (json_object ()); + count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, json); bool is_plist = !CONSP (XCAR (tail)); FOR_EACH_TAIL (tail) { @@ -427,19 +421,22 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) key_str = &key_str[1]; } /* Only add element if key is not already present. */ - if (json_object_get (*json, key_str) == NULL) + if (json_object_get (json, key_str) == NULL) { int status - = json_object_set_new (*json, key_str, lisp_to_json (value)); + = json_object_set_new (json, key_str, lisp_to_json (value)); if (status == -1) json_out_of_memory (); } } CHECK_LIST_END (tail, lisp); - clear_unwind_protect (count); - return unbind_to (count, Qnil); } - wrong_type_argument (Qjson_value_p, lisp); + else + wrong_type_argument (Qjson_value_p, lisp); + + clear_unwind_protect (count); + unbind_to (count, Qnil); + return json; } /* Convert LISP to a toplevel JSON object (array or object). Signal @@ -451,8 +448,7 @@ lisp_to_json_toplevel (Lisp_Object lisp) { if (++lisp_eval_depth > max_lisp_eval_depth) xsignal0 (Qjson_object_too_deep); - json_t *json; - lisp_to_json_toplevel_1 (lisp, &json); + json_t *json = lisp_to_json_toplevel_1 (lisp); --lisp_eval_depth; return json; } commit d12924cacb86c53a0547f73af35169db8e44d628 Author: Daniel Colascione Date: Sat Jun 9 17:45:01 2018 -0700 Correctly set last_nonmenu_event when replaying read_key_sequence can, in various circumstances, play back recorded events. Make sure that we set last_nonmenu_event as if we weren't replaying. Without this change, we leave last_nonmenu_event set to whatever it was before we started replaying, leading to spurious random keymap menu prompts appearing after reading terminal control sequences, the translation of which sometimes causes event replays. * src/keyboard.c: (grow_bool_vector): New function (read_key_sequence): Remember menu event history per-event. diff --git a/src/keyboard.c b/src/keyboard.c index c0c863f0d3..bd9292c265 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -8858,6 +8858,31 @@ void init_raw_keybuf_count (void) raw_keybuf_count = 0; } +/* Grow a vector to fit. + + On entry, *VECTOR is nil or a bool vector. Upon return, *VECTOR + contains a bool vector of size at least NEEDED_LENGTH, with any new + values to false. Return the new value of *VECTOR. */ +static Lisp_Object +grow_bool_vector (Lisp_Object *vector, int needed_length) +{ + EMACS_INT old_length = NILP (*vector) ? 0 : bool_vector_size (*vector); + if (NILP (*vector) || old_length < needed_length) + { + EMACS_INT new_length = old_length ? old_length : 64; + while (new_length < needed_length) + new_length *= 2; + Lisp_Object new_vector = + Fmake_bool_vector (make_number (needed_length), Qnil); + if (old_length) + memcpy (bool_vector_data (new_vector), + bool_vector_data (*vector), + bool_vector_bytes (old_length)); + *vector = new_vector; + } + return *vector; +} + /* Read a sequence of keys that ends with a non prefix character, storing it in KEYBUF, a buffer of size BUFSIZE. Prompt with PROMPT. @@ -8934,6 +8959,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, reading characters from the keyboard. */ int mock_input = 0; + /* This bool vector remembers whether each event in the mocked input + came from a mouse menu. We ordinarily leave it nil and create it + the first time we remember a mouse event. */ + Lisp_Object used_mouse_menu_history = Qnil; + /* If the sequence is unbound in submaps[], then keybuf[fkey.start..fkey.end-1] is a prefix in Vfunction_key_map, and fkey.map is its binding. @@ -8974,8 +9004,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, of raw_keybuf created by the outer call. */ /* raw_keybuf_count = 0; */ - last_nonmenu_event = Qnil; - delayed_switch_frame = Qnil; if (INTERACTIVE) @@ -9039,11 +9067,12 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* Start from the beginning in keybuf. */ t = 0; + last_nonmenu_event = Qnil; /* These are no-ops the first time through, but if we restart, they revert the echo area and this_command_keys to their original state. */ this_command_key_count = keys_start; - if (INTERACTIVE && t < mock_input) + if (INTERACTIVE) echo_truncate (echo_start); /* If the best binding for the current key sequence is a keymap, or @@ -9137,6 +9166,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, current_kboard->immediate_echo = false; echo_now (); } + used_mouse_menu = !NILP (used_mouse_menu_history) && + t < bool_vector_size (used_mouse_menu_history) && + bool_vector_bitref (used_mouse_menu_history, t); } /* If not, we should actually read a character. */ @@ -9150,6 +9182,10 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, key = read_char (prevent_redisplay ? -2 : NILP (prompt), current_binding, last_nonmenu_event, &used_mouse_menu, NULL); + if (used_mouse_menu || !NILP (used_mouse_menu_history)) + bool_vector_set ( + grow_bool_vector (&used_mouse_menu_history, t + 1), + t, used_mouse_menu); if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */ /* When switching to a new tty (with a new keyboard), read_char returns the new buffer, rather than -2 commit aaffae8458dcd774540e7e6b4219c8b5a9902075 Author: Daniel Colascione Date: Sat Jun 9 15:41:29 2018 -0700 Add debug facility for formatting in rr sessions The existing debug print commands don't work in rr, since they touch stderr. The new xfmt command just calls Fformat and doesn't touch the stdio streams. * src/.gdbinit: (xfmt): New GDB command. * src/print.c: (debug_format): New function. diff --git a/src/.gdbinit b/src/.gdbinit index 67dcf718e3..3cebdff5e7 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -119,6 +119,12 @@ Print the value of the lisp variable given as argument. Works only when an inferior emacs is executing. end +# Format the value and print it as a string. Works in +# an rr session and during live debugging. Calls into lisp. +define xfmt + printf "%s\n", debug_format("%S", $arg0) +end + # Print out current buffer point and boundaries define ppt set $b = current_buffer diff --git a/src/print.c b/src/print.c index 8394375220..234f44a4a5 100644 --- a/src/print.c +++ b/src/print.c @@ -855,6 +855,17 @@ safe_debug_print (Lisp_Object arg) } } +/* This function formats the given object and returns the result as a + string. Use this in contexts where you can inspect strings, but + where stderr output won't work --- e.g., while replaying rr + recordings. */ +const char * debug_format (const char *, Lisp_Object) EXTERNALLY_VISIBLE; +const char * +debug_format (const char *fmt, Lisp_Object arg) +{ + return SSDATA (CALLN (Fformat, build_string (fmt), arg)); +} + DEFUN ("error-message-string", Ferror_message_string, Serror_message_string, 1, 1, 0, commit 16015dea97b3b4da7ff66a7e822c3c26b2ab6d2b Author: Daniel Colascione Date: Sat Jun 9 13:43:05 2018 -0700 Fix typo in docstring * lisp/term/xterm.el: (xterm-paste-ending-sequence): Fix typo diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el index a4321914c1..b3b7a21635 100644 --- a/lisp/term/xterm.el +++ b/lisp/term/xterm.el @@ -74,7 +74,7 @@ string bytes that can be copied is 3/4 of this value." :type 'boolean) (defconst xterm-paste-ending-sequence "\e[201~" - "Characters send by the terminal to end a bracketed paste.") + "Characters sent by the terminal to end a bracketed paste.") (defun xterm--pasted-text () "Handle the rest of a terminal paste operation. commit 1a4c6e69db6f8861271f14338ed67aaf12cbd4c5 Author: Paul Eggert Date: Sat Jun 9 17:17:55 2018 -0700 Fix read buffer overrun on overflowed integers * src/lread.c (read_integer): Fix off-by-1 buffer overrun introduced in 2018-04-17T23:23:16Z!eggert@cs.ucla.edu. The bug could occur when Emacs read radixed integers containing more than 100 digits. Bug caught by AddressSanitizer. diff --git a/src/lread.c b/src/lread.c index d2c7eae20f..4229ff568b 100644 --- a/src/lread.c +++ b/src/lread.c @@ -2680,8 +2680,8 @@ read_integer (Lisp_Object readcharfun, EMACS_INT radix) valid = 0; if (valid < 0) valid = 1; - *p = c; - p += p < buf + sizeof buf; + if (p < buf + sizeof buf) + *p++ = c; c = READCHAR; } commit 89e2683d4430ffbe3bfe355ca389c349304bdcb9 Author: Alan Mackenzie Date: Sat Jun 9 21:39:43 2018 +0000 Implement the C++11 "using" type definition. Cease using the long obsolete c++-template-syntax-table. * lisp/progmodes/cc-align.el (c-lineup-template-args): Cease using c++-template-syntax-table. * lisp/progmodes/cc-engine.el (c-beginning-of-inheritance-list) (c-search-decl-header-end, c-beginning-of-decl-1, c-end-of-decl-1) (c-guess-continued-construct, c-guess-basic-syntax): Cease using c++-template-syntax-table. (c-guess-basic-syntax): Add CASE 5D.6 to handle C++11's "using" type definition. * lisp/progmodes/cc-langs.el (c++-make-template-syntax-table) (c++-template-syntax-table): Remove. (c-equals-type-clause-kwds, c-equals-type-clause-key): New language constants/variables. diff --git a/lisp/progmodes/cc-align.el b/lisp/progmodes/cc-align.el index 09887b02f3..1b48a5a66c 100644 --- a/lisp/progmodes/cc-align.el +++ b/lisp/progmodes/cc-align.el @@ -868,12 +868,11 @@ returned if there's no template argument on the first line. Works with: template-args-cont." (save-excursion - (c-with-syntax-table c++-template-syntax-table - (beginning-of-line) - (backward-up-list 1) - (if (and (eq (char-after) ?<) - (zerop (c-forward-token-2 1 nil (c-point 'eol)))) - (vector (current-column)))))) + (beginning-of-line) + (backward-up-list 1) + (if (and (eq (char-after) ?<) + (zerop (c-forward-token-2 1 nil (c-point 'eol)))) + (vector (current-column))))) (defun c-lineup-ObjC-method-call (langelem) "Line up selector args as Emacs Lisp mode does with function args: diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 3d9e4fa0d3..36f5196c5e 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -9510,11 +9510,10 @@ comment at the start of cc-engine.el for more info." ;; back we should search. ;; ;; This function might do hidden buffer changes. - (c-with-syntax-table c++-template-syntax-table - (c-backward-token-2 0 t lim) - (while (and (or (looking-at c-symbol-start) - (looking-at "[<,]\\|::")) - (zerop (c-backward-token-2 1 t lim)))))) + (c-backward-token-2 0 t lim) + (while (and (or (looking-at c-symbol-start) + (looking-at "[<,]\\|::")) + (zerop (c-backward-token-2 1 t lim))))) (defun c-in-method-def-p () ;; Return nil if we aren't in a method definition, otherwise the @@ -9890,11 +9889,10 @@ comment at the start of cc-engine.el for more info." (and (c-safe (c-backward-sexp) t) (looking-at c-opt-op-identifier-prefix))) (and (eq (char-before) ?<) - (c-with-syntax-table c++-template-syntax-table - (if (c-safe (goto-char (c-up-list-forward (point)))) - t - (goto-char (point-max)) - nil))))) + (if (c-safe (goto-char (c-up-list-forward (point)))) + t + (goto-char (point-max)) + nil)))) (setq base (point))) (while (and @@ -9987,28 +9985,25 @@ comment at the start of cc-engine.el for more info." ;; potentially can search over a large amount of text.). Take special ;; pains not to get mislead by C++'s "operator=", and the like. (if (and (eq move 'previous) - (c-with-syntax-table (if (c-major-mode-is 'c++-mode) - c++-template-syntax-table - (syntax-table)) - (save-excursion - (and - (progn - (while ; keep going back to "[;={"s until we either find - ; no more, or get to one which isn't an "operator =" - (and (c-syntactic-re-search-forward "[;={]" start t t t) - (eq (char-before) ?=) - c-overloadable-operators-regexp - c-opt-op-identifier-prefix - (save-excursion - (eq (c-backward-token-2) 0) - (looking-at c-overloadable-operators-regexp) - (eq (c-backward-token-2) 0) - (looking-at c-opt-op-identifier-prefix)))) - (eq (char-before) ?=)) - (c-syntactic-re-search-forward "[;{]" start t t) - (eq (char-before) ?{) - (c-safe (goto-char (c-up-list-forward (point))) t) - (not (c-syntactic-re-search-forward ";" start t t)))))) + (save-excursion + (and + (progn + (while ; keep going back to "[;={"s until we either find + ; no more, or get to one which isn't an "operator =" + (and (c-syntactic-re-search-forward "[;={]" start t t t) + (eq (char-before) ?=) + c-overloadable-operators-regexp + c-opt-op-identifier-prefix + (save-excursion + (eq (c-backward-token-2) 0) + (looking-at c-overloadable-operators-regexp) + (eq (c-backward-token-2) 0) + (looking-at c-opt-op-identifier-prefix)))) + (eq (char-before) ?=)) + (c-syntactic-re-search-forward "[;{]" start t t) + (eq (char-before) ?{) + (c-safe (goto-char (c-up-list-forward (point))) t) + (not (c-syntactic-re-search-forward ";" start t t))))) (cons 'same nil) (cons move nil))))) @@ -10023,10 +10018,7 @@ comment at the start of cc-engine.el for more info." ;; `c-end-of-macro' instead in those cases. ;; ;; This function might do hidden buffer changes. - (let ((start (point)) - (decl-syntax-table (if (c-major-mode-is 'c++-mode) - c++-template-syntax-table - (syntax-table)))) + (let ((start (point))) (catch 'return (c-search-decl-header-end) @@ -10047,34 +10039,32 @@ comment at the start of cc-engine.el for more info." (throw 'return nil))) (if (or (not c-opt-block-decls-with-vars-key) (save-excursion - (c-with-syntax-table decl-syntax-table - (let ((lim (point))) - (goto-char start) - (not (and - ;; Check for `c-opt-block-decls-with-vars-key' - ;; before the first paren. - (c-syntactic-re-search-forward - (concat "[;=([{]\\|\\(" - c-opt-block-decls-with-vars-key - "\\)") - lim t t t) - (match-beginning 1) - (not (eq (char-before) ?_)) - ;; Check that the first following paren is - ;; the block. - (c-syntactic-re-search-forward "[;=([{]" - lim t t t) - (eq (char-before) ?{))))))) + (let ((lim (point))) + (goto-char start) + (not (and + ;; Check for `c-opt-block-decls-with-vars-key' + ;; before the first paren. + (c-syntactic-re-search-forward + (concat "[;=\(\[{]\\|\\(" + c-opt-block-decls-with-vars-key + "\\)") + lim t t t) + (match-beginning 1) + (not (eq (char-before) ?_)) + ;; Check that the first following paren is + ;; the block. + (c-syntactic-re-search-forward "[;=\(\[{]" + lim t t t) + (eq (char-before) ?{)))))) ;; The declaration doesn't have any of the ;; `c-opt-block-decls-with-vars' keywords in the ;; beginning, so it ends here at the end of the block. (throw 'return t))) - (c-with-syntax-table decl-syntax-table - (while (progn - (if (eq (char-before) ?\;) - (throw 'return t)) - (c-syntactic-re-search-forward ";" nil 'move t)))) + (while (progn + (if (eq (char-before) ?\;) + (throw 'return t)) + (c-syntactic-re-search-forward ";" nil 'move t))) nil))) (defun c-looking-at-decl-block (_containing-sexp goto-start &optional limit) @@ -11460,17 +11450,15 @@ comment at the start of cc-engine.el for more info." ((and (c-major-mode-is 'c++-mode) (save-excursion (goto-char indent-point) - (c-with-syntax-table c++-template-syntax-table - (setq placeholder (c-up-list-backward))) + (setq placeholder (c-up-list-backward)) (and placeholder (eq (char-after placeholder) ?<) (/= (char-before placeholder) ?<) (progn (goto-char (1+ placeholder)) (not (looking-at c-<-op-cont-regexp)))))) - (c-with-syntax-table c++-template-syntax-table - (goto-char placeholder) - (c-beginning-of-statement-1 containing-sexp t)) + (goto-char placeholder) + (c-beginning-of-statement-1 containing-sexp t) (if (save-excursion (c-backward-syntactic-ws containing-sexp) (eq (char-before) ?<)) @@ -12130,21 +12118,38 @@ comment at the start of cc-engine.el for more info." ;; NB: No c-after-special-operator-id stuff in this ;; clause - we assume only C++ needs it. (c-syntactic-skip-backward "^;,=" lim t)) + (setq placeholder (point)) (memq (char-before) '(?, ?= ?<))) (cond + ;; CASE 5D.6: Something like C++11's "using foo = " + ((save-excursion + (and (eq (char-before placeholder) ?=) + (goto-char placeholder) + (eq (c-backward-token-2 1 nil lim) 0) + (eq (point) (1- placeholder)) + (eq (c-beginning-of-statement-1 lim) 'same) + (looking-at c-equals-type-clause-key) + (let ((preserve-point (point))) + (when + (and + (eq (c-forward-token-2 1 nil nil) 0) + (c-on-identifier)) + (setq placeholder preserve-point))))) + (c-add-syntax + 'statement-cont placeholder) + ) + ;; CASE 5D.3: perhaps a template list continuation? ((and (c-major-mode-is 'c++-mode) (save-excursion (save-restriction - (c-with-syntax-table c++-template-syntax-table - (goto-char indent-point) - (setq placeholder (c-up-list-backward)) - (and placeholder - (eq (char-after placeholder) ?<)))))) - (c-with-syntax-table c++-template-syntax-table - (goto-char placeholder) - (c-beginning-of-statement-1 lim t)) + (goto-char indent-point) + (setq placeholder (c-up-list-backward)) + (and placeholder + (eq (char-after placeholder) ?<))))) + (goto-char placeholder) + (c-beginning-of-statement-1 lim t) (if (save-excursion (c-backward-syntactic-ws lim) (eq (char-before) ?<)) @@ -12168,8 +12173,7 @@ comment at the start of cc-engine.el for more info." (and (looking-at c-class-key) (zerop (c-forward-token-2 2 nil indent-point)) (if (eq (char-after) ?<) - (c-with-syntax-table c++-template-syntax-table - (zerop (c-forward-token-2 1 t indent-point))) + (zerop (c-forward-token-2 1 t indent-point)) t) (eq (char-after) ?:)))) (goto-char placeholder) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 53cb7f7f72..1b44c75fe6 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -392,27 +392,6 @@ The syntax tables aren't stored directly since they're quite large." ;; the constants in this file are evaluated. t (funcall (c-lang-const c-make-mode-syntax-table))) -(c-lang-defconst c++-make-template-syntax-table - ;; A variant of `c++-mode-syntax-table' that defines `<' and `>' as - ;; parenthesis characters. Used temporarily when template argument - ;; lists are parsed. Note that this encourages incorrect parsing of - ;; templates since they might contain normal operators that uses the - ;; '<' and '>' characters. Therefore this syntax table might go - ;; away when CC Mode handles templates correctly everywhere. WHILE - ;; THIS SYNTAX TABLE IS CURRENT, `c-parse-state' MUST _NOT_ BE - ;; CALLED!!! - t nil - (java c++) `(lambda () - (let ((table (funcall ,(c-lang-const c-make-mode-syntax-table)))) - (modify-syntax-entry ?< "(>" table) - (modify-syntax-entry ?> ")<" table) - table))) -(c-lang-defvar c++-template-syntax-table - (and (c-lang-const c++-make-template-syntax-table) - ;; The next eval remove a superfluous ' from '(lambda. This - ;; gets rid of compilation warnings. - (funcall (eval (c-lang-const c++-make-template-syntax-table))))) - (c-lang-defconst c-make-no-parens-syntax-table ;; A variant of the standard syntax table which is used to find matching ;; "<"s and ">"s which have been marked as parens using syntax table @@ -2210,6 +2189,18 @@ will be handled." pike (append (c-lang-const c-class-decl-kwds) '("constant"))) +(c-lang-defconst c-equals-type-clause-kwds + "Keywords which are followed by an identifier then an \"=\" + sign, which declares the identifier to be a type." + t nil + c++ '("using")) + +(c-lang-defconst c-equals-type-clause-key + ;; A regular expression which matches any member of + ;; `c-equals-type-clause-kwds'. + t (c-make-keywords-re t (c-lang-const c-equals-type-clause-kwds))) +(c-lang-defvar c-equals-type-clause-key (c-lang-const c-equals-type-clause-key)) + (c-lang-defconst c-modifier-kwds "Keywords that can prefix normal declarations of identifiers \(and typically act as flags). Things like argument declarations commit a66a3b7f51792aa2a91c16ed9121d7e9efea4536 Author: Daniel Colascione Date: Sat Jun 9 13:14:11 2018 -0700 Improve robustness xterm event processing We used to treat the start of a focus-in, focus-out, and the start of a paste sequence as normal events bound in global-map, but this approach produces problems when we recognize events in the middle of actions that don't immediately dispatch to the command loop. Now we handle these events internally inside read-key, translating the focus events to nothing and paste-start into an xterm-paste event that neatly encapsulates the entire paste sequence. * lisp/term/xterm.el: (xterm-paste): Accept an event argument; insert text from event. (xterm-translate-focus-in,xterm-translate-focus-out) (xterm-translate-bracketed-paste): New functions. (xterm-handle-focus-in,xterm-handle-focus-out): Remove. (xterm-rxvt-function-map): Bind new translation functions. diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el index 06a9d443bf..a4321914c1 100644 --- a/lisp/term/xterm.el +++ b/lisp/term/xterm.el @@ -95,24 +95,41 @@ Return the pasted text as a string." (decode-coding-region (point-min) (point) (keyboard-coding-system) t))))) -(defun xterm-paste () +(defun xterm-paste (event) "Handle the start of a terminal paste operation." - (interactive) - (let* ((pasted-text (xterm--pasted-text)) + (interactive "e") + (unless (eq (car-safe event) 'xterm-paste) + (error "xterm-paste must be found to xterm-paste event")) + (let* ((pasted-text (nth 1 event)) (interprogram-paste-function (lambda () pasted-text))) (yank))) +;; Put xterm-paste itself in global-map because, after translation, +;; it's just a normal input event. (define-key global-map [xterm-paste] #'xterm-paste) -(defun xterm-handle-focus-in () - (interactive) - (handle-focus-in)) -(define-key global-map [xterm-focus-in] #'xterm-handle-focus-in) +;; By returning an empty key sequence, these two functions perform the +;; moral equivalent of the kind of transparent event processing done +;; by read-event's handling of special-event-map, but inside +;; read-key-sequence (which can recognize multi-character terminal +;; notifications) instead of read-event (which can't). -(defun xterm-handle-focus-out () - (interactive) - (handle-focus-out)) -(define-key global-map [xterm-focus-out] #'xterm-handle-focus-out) +(defun xterm-translate-focus-in (_prompt) + (handle-focus-in) + []) + +(defun xterm-translate-focus-out (_prompt) + (handle-focus-out) + []) + +;; Similarly, we want to transparently slurp the entirety of a +;; bracketed paste and encapsulate it into a single event. We used to +;; just slurp up the bracketed paste content in the event handler, but +;; this strategy can produce unexpected results in a caller manually +;; looping on read-key and buffering input for later processing. + +(defun xterm-translate-bracketed-paste (_prompt) + (vector (list 'xterm-paste (xterm--pasted-text)))) (defvar xterm-rxvt-function-map (let ((map (make-sparse-keymap))) @@ -142,12 +159,15 @@ Return the pasted text as a string." (define-key map "\e[13~" [f3]) (define-key map "\e[14~" [f4]) - ;; Recognize the start of a bracketed paste sequence. The handler - ;; internally recognizes the end. - (define-key map "\e[200~" [xterm-paste]) + ;; Recognize the start of a bracketed paste sequence. + ;; The translation function internally recognizes the end. + (define-key map "\e[200~" #'xterm-translate-bracketed-paste) - (define-key map "\e[I" [xterm-focus-in]) - (define-key map "\e[O" [xterm-focus-out]) + ;; These translation functions actually call the focus handlers + ;; internally and return an empty sequence, causing us to go on to + ;; read the next event. + (define-key map "\e[I" #'xterm-translate-focus-in) + (define-key map "\e[O" #'xterm-translate-focus-out) map) "Keymap of escape sequences, shared between xterm and rxvt support.") commit 66ad98685afa9ee3bc1ec2aeb116f41a2a7875b3 Author: Alan Mackenzie Date: Sat Jun 9 17:34:46 2018 +0000 CC Mode: In brace lists, anchor an elt on its predecessor, not on first elt * lisp/progmodes/cc-engine.el (c-beginning-of-statement-1): At the end, accept "." as a unary operator (which it now is in brace lists in, e.g., C Mode). (c-guess-basic-syntax): Just before CASE 9C, move back to the previous brace list entry in the block, rather than to the first one. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index d1380ff6f6..3d9e4fa0d3 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -1282,7 +1282,7 @@ comment at the start of cc-engine.el for more info." (c-backward-syntactic-ws) ;; protect AWK post-inc/decrement operators, etc. (and (not (c-at-vsemi-p (point))) - (/= (skip-chars-backward "-+!*&~@`#") 0))) + (/= (skip-chars-backward "-.+!*&~@`#") 0))) (setq pos (point))) (goto-char pos) ret))) @@ -12608,18 +12608,21 @@ comment at the start of cc-engine.el for more info." (c-add-stmt-syntax 'brace-list-close nil t lim paren-state))) (t - ;; Prepare for the rest of the cases below by going to the - ;; token following the opening brace - (if (consp special-brace-list) - (progn - (goto-char (car (car special-brace-list))) - (c-forward-token-2 1 nil indent-point)) - (goto-char containing-sexp)) - (forward-char) - (let ((start (point))) - (c-forward-syntactic-ws indent-point) - (goto-char (max start (c-point 'bol)))) - (c-skip-ws-forward indent-point) + ;; Prepare for the rest of the cases below by going back to the + ;; previous entry, or BOI before that, providing that this is + ;; inside the enclosing brace. + (goto-char indent-point) + (c-beginning-of-statement-1 containing-sexp nil nil t) + (when (/= (point) indent-point) + (if (> (c-point 'boi) containing-sexp) + (goto-char (c-point 'boi)) + (if (consp special-brace-list) + (progn + (goto-char (caar special-brace-list)) + (c-forward-token-2 1 nil indent-point)) + (goto-char containing-sexp)) + (forward-char) + (c-skip-ws-forward indent-point))) (cond ;; CASE 9C: we're looking at the first line in a brace-list commit b4dcac2d6ae376788dca11b88b874a9ecaf986df Author: Philipp Stephani Date: Sat Jun 2 22:35:22 2018 +0200 Make error checking for thread functions stricter. * src/systhread.c (sys_thread_create): Change return type to bool. Check for errors returned by pthread_attr_setstacksize and pthread_attr_destroy. (sys_mutex_init): Abort on errors. Enable mutex checks when checking is enabled. (sys_cond_init): Abort on errors. (sys_mutex_lock, sys_mutex_unlock, sys_cond_wait) (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy): Check for errors in debug mode. diff --git a/src/systhread.c b/src/systhread.c index e972ed398a..d53b5c207b 100644 --- a/src/systhread.c +++ b/src/systhread.c @@ -18,6 +18,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include +#include #include "lisp.h" #ifdef HAVE_NS @@ -80,11 +82,11 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u) return t == u; } -int +bool sys_thread_create (sys_thread_t *t, const char *name, thread_creation_function *func, void *datum) { - return 0; + return false; } void @@ -103,43 +105,77 @@ sys_thread_yield (void) void sys_mutex_init (sys_mutex_t *mutex) { - pthread_mutex_init (mutex, NULL); + pthread_mutexattr_t *attr_ptr; +#ifdef ENABLE_CHECKING + pthread_mutexattr_t attr; + { + int error = pthread_mutexattr_init (&attr); + eassert (error == 0); + error = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); + eassert (error == 0); + } + attr_ptr = &attr; +#else + attr_ptr = NULL; +#endif + int error = pthread_mutex_init (mutex, attr_ptr); + /* We could get ENOMEM. Can't do anything except aborting. */ + if (error != 0) + { + fprintf (stderr, "\npthread_mutex_init failed: %s\n", strerror (error)); + emacs_abort (); + } +#ifdef ENABLE_CHECKING + error = pthread_mutexattr_destroy (&attr); + eassert (error == 0); +#endif } void sys_mutex_lock (sys_mutex_t *mutex) { - pthread_mutex_lock (mutex); + int error = pthread_mutex_lock (mutex); + eassert (error == 0); } void sys_mutex_unlock (sys_mutex_t *mutex) { - pthread_mutex_unlock (mutex); + int error = pthread_mutex_unlock (mutex); + eassert (error == 0); } void sys_cond_init (sys_cond_t *cond) { - pthread_cond_init (cond, NULL); + int error = pthread_cond_init (cond, NULL); + /* We could get ENOMEM. Can't do anything except aborting. */ + if (error != 0) + { + fprintf (stderr, "\npthread_cond_init failed: %s\n", strerror (error)); + emacs_abort (); + } } void sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) { - pthread_cond_wait (cond, mutex); + int error = pthread_cond_wait (cond, mutex); + eassert (error == 0); } void sys_cond_signal (sys_cond_t *cond) { - pthread_cond_signal (cond); + int error = pthread_cond_signal (cond); + eassert (error == 0); } void sys_cond_broadcast (sys_cond_t *cond) { - pthread_cond_broadcast (cond); + int error = pthread_cond_broadcast (cond); + eassert (error == 0); #ifdef HAVE_NS /* Send an app defined event to break out of the NS run loop. It seems that if ns_select is running the NS run loop, this @@ -152,7 +188,8 @@ sys_cond_broadcast (sys_cond_t *cond) void sys_cond_destroy (sys_cond_t *cond) { - pthread_cond_destroy (cond); + int error = pthread_cond_destroy (cond); + eassert (error == 0); } sys_thread_t @@ -167,22 +204,25 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u) return pthread_equal (t, u); } -int +bool sys_thread_create (sys_thread_t *thread_ptr, const char *name, thread_creation_function *func, void *arg) { pthread_attr_t attr; - int result = 0; + bool result = false; if (pthread_attr_init (&attr)) - return 0; + return false; /* Avoid crash on macOS with deeply nested GC (Bug#30364). */ size_t stack_size; size_t required_stack_size = sizeof (void *) * 1024 * 1024; if (pthread_attr_getstacksize (&attr, &stack_size) == 0 && stack_size < required_stack_size) - pthread_attr_setstacksize (&attr, required_stack_size); + { + if (pthread_attr_setstacksize (&attr, required_stack_size) != 0) + goto out; + } if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) { @@ -193,7 +233,9 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, #endif } - pthread_attr_destroy (&attr); + out: ; + int error = pthread_attr_destroy (&attr); + eassert (error == 0); return result; } @@ -359,7 +401,7 @@ w32_beginthread_wrapper (void *arg) (void)thread_start_address (arg); } -int +bool sys_thread_create (sys_thread_t *thread_ptr, const char *name, thread_creation_function *func, void *arg) { @@ -383,7 +425,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, rule in many places... */ thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); if (thandle == (uintptr_t)-1L) - return 0; + return false; /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit number, as the sys_thread_t type, because that ID is the only @@ -398,7 +440,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, Therefore, we return some more or less arbitrary value of the thread ID from this function. */ *thread_ptr = thandle & 0xFFFFFFFF; - return 1; + return true; } void diff --git a/src/systhread.h b/src/systhread.h index 5dbb12dffb..3805cb261f 100644 --- a/src/systhread.h +++ b/src/systhread.h @@ -19,6 +19,18 @@ along with GNU Emacs. If not, see . */ #ifndef SYSTHREAD_H #define SYSTHREAD_H +#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__)) +#else +# define ATTRIBUTE_WARN_UNUSED_RESULT +#endif + #ifdef THREADS_ENABLED #ifdef HAVE_PTHREAD @@ -99,12 +111,14 @@ extern void sys_cond_signal (sys_cond_t *); extern void sys_cond_broadcast (sys_cond_t *); extern void sys_cond_destroy (sys_cond_t *); -extern sys_thread_t sys_thread_self (void); -extern bool sys_thread_equal (sys_thread_t, sys_thread_t); +extern sys_thread_t sys_thread_self (void) + ATTRIBUTE_WARN_UNUSED_RESULT; +extern bool sys_thread_equal (sys_thread_t, sys_thread_t) + ATTRIBUTE_WARN_UNUSED_RESULT; -extern int sys_thread_create (sys_thread_t *, const char *, - thread_creation_function *, - void *); +extern bool sys_thread_create (sys_thread_t *, const char *, + thread_creation_function *, void *) + ATTRIBUTE_WARN_UNUSED_RESULT; extern void sys_thread_yield (void);