diff options
| author | Lars Ingebrigtsen | 2019-10-13 03:12:11 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2019-10-13 03:12:11 +0200 |
| commit | db9ba7ca014a3437fc571b0890fa9ab16c08cfe0 (patch) | |
| tree | bb8a0a038651314475f98877bd989f6d7ff2fdd0 /src | |
| parent | 297f333a13b1f126e3f9c378ab856b970ee80283 (diff) | |
| download | emacs-db9ba7ca014a3437fc571b0890fa9ab16c08cfe0.tar.gz emacs-db9ba7ca014a3437fc571b0890fa9ab16c08cfe0.zip | |
Protect against segfaults in copy-keymap
* src/keymap.c (copy_keymap_1): Factor out and refuse to recurse
infinitely (bug#7496).
(Fcopy_keymap): ... from here.
(copy_keymap_item): Pass on the depth parameter.
Diffstat (limited to 'src')
| -rw-r--r-- | src/keymap.c | 70 |
1 files changed, 42 insertions, 28 deletions
diff --git a/src/keymap.c b/src/keymap.c index da2786c8449..5aed4129bb7 100644 --- a/src/keymap.c +++ b/src/keymap.c | |||
| @@ -912,8 +912,10 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def) | |||
| 912 | return def; | 912 | return def; |
| 913 | } | 913 | } |
| 914 | 914 | ||
| 915 | static Lisp_Object copy_keymap_1 (Lisp_Object keymap, int depth); | ||
| 916 | |||
| 915 | static Lisp_Object | 917 | static Lisp_Object |
| 916 | copy_keymap_item (Lisp_Object elt) | 918 | copy_keymap_item (Lisp_Object elt, int depth) |
| 917 | { | 919 | { |
| 918 | Lisp_Object res, tem; | 920 | Lisp_Object res, tem; |
| 919 | 921 | ||
| @@ -943,7 +945,7 @@ copy_keymap_item (Lisp_Object elt) | |||
| 943 | elt = XCDR (elt); | 945 | elt = XCDR (elt); |
| 944 | tem = XCAR (elt); | 946 | tem = XCAR (elt); |
| 945 | if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) | 947 | if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) |
| 946 | XSETCAR (elt, Fcopy_keymap (tem)); | 948 | XSETCAR (elt, copy_keymap_1 (tem, depth)); |
| 947 | tem = XCDR (elt); | 949 | tem = XCDR (elt); |
| 948 | } | 950 | } |
| 949 | } | 951 | } |
| @@ -964,40 +966,29 @@ copy_keymap_item (Lisp_Object elt) | |||
| 964 | tem = XCDR (elt); | 966 | tem = XCDR (elt); |
| 965 | } | 967 | } |
| 966 | if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) | 968 | if (CONSP (tem) && EQ (XCAR (tem), Qkeymap)) |
| 967 | XSETCDR (elt, Fcopy_keymap (tem)); | 969 | XSETCDR (elt, copy_keymap_1 (tem, depth)); |
| 968 | } | 970 | } |
| 969 | else if (EQ (XCAR (tem), Qkeymap)) | 971 | else if (EQ (XCAR (tem), Qkeymap)) |
| 970 | res = Fcopy_keymap (elt); | 972 | res = copy_keymap_1 (elt, depth); |
| 971 | } | 973 | } |
| 972 | return res; | 974 | return res; |
| 973 | } | 975 | } |
| 974 | 976 | ||
| 975 | static void | 977 | static void |
| 976 | copy_keymap_1 (Lisp_Object chartable, Lisp_Object idx, Lisp_Object elt) | 978 | copy_keymap_set_char_table (Lisp_Object chartable, Lisp_Object idx, |
| 979 | Lisp_Object elt) | ||
| 977 | { | 980 | { |
| 978 | Fset_char_table_range (chartable, idx, copy_keymap_item (elt)); | 981 | Fset_char_table_range (chartable, idx, copy_keymap_item (elt, 0)); |
| 979 | } | 982 | } |
| 980 | 983 | ||
| 981 | DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, | 984 | static Lisp_Object |
| 982 | doc: /* Return a copy of the keymap KEYMAP. | 985 | copy_keymap_1 (Lisp_Object keymap, int depth) |
| 983 | |||
| 984 | Note that this is almost never needed. If you want a keymap that's like | ||
| 985 | another yet with a few changes, you should use map inheritance rather | ||
| 986 | than copying. I.e. something like: | ||
| 987 | |||
| 988 | (let ((map (make-sparse-keymap))) | ||
| 989 | (set-keymap-parent map <theirmap>) | ||
| 990 | (define-key map ...) | ||
| 991 | ...) | ||
| 992 | |||
| 993 | After performing `copy-keymap', the copy starts out with the same definitions | ||
| 994 | of KEYMAP, but changing either the copy or KEYMAP does not affect the other. | ||
| 995 | Any key definitions that are subkeymaps are recursively copied. | ||
| 996 | However, a key definition which is a symbol whose definition is a keymap | ||
| 997 | is not copied. */) | ||
| 998 | (Lisp_Object keymap) | ||
| 999 | { | 986 | { |
| 1000 | Lisp_Object copy, tail; | 987 | Lisp_Object copy, tail; |
| 988 | |||
| 989 | if (depth > 100) | ||
| 990 | error ("Possible infinite recursion when copying keymap"); | ||
| 991 | |||
| 1001 | keymap = get_keymap (keymap, 1, 0); | 992 | keymap = get_keymap (keymap, 1, 0); |
| 1002 | copy = tail = list1 (Qkeymap); | 993 | copy = tail = list1 (Qkeymap); |
| 1003 | keymap = XCDR (keymap); /* Skip the `keymap' symbol. */ | 994 | keymap = XCDR (keymap); /* Skip the `keymap' symbol. */ |
| @@ -1008,22 +999,22 @@ is not copied. */) | |||
| 1008 | if (CHAR_TABLE_P (elt)) | 999 | if (CHAR_TABLE_P (elt)) |
| 1009 | { | 1000 | { |
| 1010 | elt = Fcopy_sequence (elt); | 1001 | elt = Fcopy_sequence (elt); |
| 1011 | map_char_table (copy_keymap_1, Qnil, elt, elt); | 1002 | map_char_table (copy_keymap_set_char_table, Qnil, elt, elt); |
| 1012 | } | 1003 | } |
| 1013 | else if (VECTORP (elt)) | 1004 | else if (VECTORP (elt)) |
| 1014 | { | 1005 | { |
| 1015 | int i; | 1006 | int i; |
| 1016 | elt = Fcopy_sequence (elt); | 1007 | elt = Fcopy_sequence (elt); |
| 1017 | for (i = 0; i < ASIZE (elt); i++) | 1008 | for (i = 0; i < ASIZE (elt); i++) |
| 1018 | ASET (elt, i, copy_keymap_item (AREF (elt, i))); | 1009 | ASET (elt, i, copy_keymap_item (AREF (elt, i), depth + 1)); |
| 1019 | } | 1010 | } |
| 1020 | else if (CONSP (elt)) | 1011 | else if (CONSP (elt)) |
| 1021 | { | 1012 | { |
| 1022 | if (EQ (XCAR (elt), Qkeymap)) | 1013 | if (EQ (XCAR (elt), Qkeymap)) |
| 1023 | /* This is a sub keymap. */ | 1014 | /* This is a sub keymap. */ |
| 1024 | elt = Fcopy_keymap (elt); | 1015 | elt = copy_keymap_1 (elt, depth + 1); |
| 1025 | else | 1016 | else |
| 1026 | elt = Fcons (XCAR (elt), copy_keymap_item (XCDR (elt))); | 1017 | elt = Fcons (XCAR (elt), copy_keymap_item (XCDR (elt), depth + 1)); |
| 1027 | } | 1018 | } |
| 1028 | XSETCDR (tail, list1 (elt)); | 1019 | XSETCDR (tail, list1 (elt)); |
| 1029 | tail = XCDR (tail); | 1020 | tail = XCDR (tail); |
| @@ -1032,6 +1023,29 @@ is not copied. */) | |||
| 1032 | XSETCDR (tail, keymap); | 1023 | XSETCDR (tail, keymap); |
| 1033 | return copy; | 1024 | return copy; |
| 1034 | } | 1025 | } |
| 1026 | |||
| 1027 | DEFUN ("copy-keymap", Fcopy_keymap, Scopy_keymap, 1, 1, 0, | ||
| 1028 | doc: /* Return a copy of the keymap KEYMAP. | ||
| 1029 | |||
| 1030 | Note that this is almost never needed. If you want a keymap that's like | ||
| 1031 | another yet with a few changes, you should use map inheritance rather | ||
| 1032 | than copying. I.e. something like: | ||
| 1033 | |||
| 1034 | (let ((map (make-sparse-keymap))) | ||
| 1035 | (set-keymap-parent map <theirmap>) | ||
| 1036 | (define-key map ...) | ||
| 1037 | ...) | ||
| 1038 | |||
| 1039 | After performing `copy-keymap', the copy starts out with the same definitions | ||
| 1040 | of KEYMAP, but changing either the copy or KEYMAP does not affect the other. | ||
| 1041 | Any key definitions that are subkeymaps are recursively copied. | ||
| 1042 | However, a key definition which is a symbol whose definition is a keymap | ||
| 1043 | is not copied. */) | ||
| 1044 | (Lisp_Object keymap) | ||
| 1045 | { | ||
| 1046 | return copy_keymap_1 (keymap, 0); | ||
| 1047 | } | ||
| 1048 | |||
| 1035 | 1049 | ||
| 1036 | /* Simple Keymap mutators and accessors. */ | 1050 | /* Simple Keymap mutators and accessors. */ |
| 1037 | 1051 | ||