aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Antipov2014-06-25 14:36:51 +0400
committerDmitry Antipov2014-06-25 14:36:51 +0400
commit5697ca55cb79817a6704c344cc76d866ee2e1699 (patch)
tree3d9cace5c0dd430485eb16697cb6c045553eb3ae
parent9a214b9800b7c01d8a473a2564e8f57215990b24 (diff)
downloademacs-5697ca55cb79817a6704c344cc76d866ee2e1699.tar.gz
emacs-5697ca55cb79817a6704c344cc76d866ee2e1699.zip
Do not allow out-of-range character position in Fcompare_strings.
* src/fns.c (validate_subarray): Add prototype. (Fcompare_substring): Use validate_subarray to check ranges. Adjust comment to mention that the semantics was changed. Also see http://lists.gnu.org/archive/html/emacs-devel/2014-06/msg00447.html. * lisp/files.el (dir-locals-find-file, file-relative-name): * lisp/info.el (Info-complete-menu-item): * lisp/minibuffer.el (completion-table-subvert): Prefer string-prefix-p to compare-strings to avoid out-of-range errors. * lisp/subr.el (string-prefix-p): Adjust to match strict range checking in compare-strings. * test/automated/fns-tests.el (fns-tests-compare-string): New test.
-rw-r--r--lisp/ChangeLog9
-rw-r--r--lisp/files.el17
-rw-r--r--lisp/info.el4
-rw-r--r--lisp/minibuffer.el6
-rw-r--r--lisp/subr.el10
-rw-r--r--src/ChangeLog8
-rw-r--r--src/fns.c65
-rw-r--r--test/ChangeLog4
-rw-r--r--test/automated/fns-tests.el31
9 files changed, 90 insertions, 64 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 80cdb66425c..c3951a08c0a 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,12 @@
12014-06-25 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * files.el (dir-locals-find-file, file-relative-name):
4 * info.el (Info-complete-menu-item):
5 * minibuffer.el (completion-table-subvert): Prefer string-prefix-p
6 to compare-strings to avoid out-of-range errors.
7 * subr.el (string-prefix-p): Adjust to match strict range
8 checking in compare-strings.
9
12014-06-24 Leonard Randall <leonard.a.randall@gmail.com> (tiny change) 102014-06-24 Leonard Randall <leonard.a.randall@gmail.com> (tiny change)
2 11
3 * textmodes/reftex-parse.el (reftex-using-biblatex-p): Make search 12 * textmodes/reftex-parse.el (reftex-using-biblatex-p): Make search
diff --git a/lisp/files.el b/lisp/files.el
index 9017cc96703..65f2009c7ce 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -3659,10 +3659,9 @@ of no valid cache entry."
3659;;; (setq locals-file nil)) 3659;;; (setq locals-file nil))
3660 ;; Find the best cached value in `dir-locals-directory-cache'. 3660 ;; Find the best cached value in `dir-locals-directory-cache'.
3661 (dolist (elt dir-locals-directory-cache) 3661 (dolist (elt dir-locals-directory-cache)
3662 (when (and (eq t (compare-strings file nil (length (car elt)) 3662 (when (and (string-prefix-p (car elt) file
3663 (car elt) nil nil 3663 (memq system-type
3664 (memq system-type 3664 '(windows-nt cygwin ms-dos)))
3665 '(windows-nt cygwin ms-dos))))
3666 (> (length (car elt)) (length (car dir-elt)))) 3665 (> (length (car elt)) (length (car dir-elt))))
3667 (setq dir-elt elt))) 3666 (setq dir-elt elt)))
3668 (if (and dir-elt 3667 (if (and dir-elt
@@ -4507,18 +4506,14 @@ on a DOS/Windows machine, it returns FILENAME in expanded form."
4507 (let ((ancestor ".") 4506 (let ((ancestor ".")
4508 (filename-dir (file-name-as-directory filename))) 4507 (filename-dir (file-name-as-directory filename)))
4509 (while (not 4508 (while (not
4510 (or 4509 (or (string-prefix-p directory filename-dir fold-case)
4511 (eq t (compare-strings filename-dir nil (length directory) 4510 (string-prefix-p directory filename fold-case)))
4512 directory nil nil fold-case))
4513 (eq t (compare-strings filename nil (length directory)
4514 directory nil nil fold-case))))
4515 (setq directory (file-name-directory (substring directory 0 -1)) 4511 (setq directory (file-name-directory (substring directory 0 -1))
4516 ancestor (if (equal ancestor ".") 4512 ancestor (if (equal ancestor ".")
4517 ".." 4513 ".."
4518 (concat "../" ancestor)))) 4514 (concat "../" ancestor))))
4519 ;; Now ancestor is empty, or .., or ../.., etc. 4515 ;; Now ancestor is empty, or .., or ../.., etc.
4520 (if (eq t (compare-strings filename nil (length directory) 4516 (if (string-prefix-p directory filename fold-case)
4521 directory nil nil fold-case))
4522 ;; We matched within FILENAME's directory part. 4517 ;; We matched within FILENAME's directory part.
4523 ;; Add the rest of FILENAME onto ANCESTOR. 4518 ;; Add the rest of FILENAME onto ANCESTOR.
4524 (let ((rest (substring filename (length directory)))) 4519 (let ((rest (substring filename (length directory))))
diff --git a/lisp/info.el b/lisp/info.el
index 89ca8bdbe33..405d6a22449 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -2691,9 +2691,7 @@ Because of ambiguities, this should be concatenated with something like
2691 (equal (nth 1 Info-complete-cache) Info-current-node) 2691 (equal (nth 1 Info-complete-cache) Info-current-node)
2692 (equal (nth 2 Info-complete-cache) Info-complete-next-re) 2692 (equal (nth 2 Info-complete-cache) Info-complete-next-re)
2693 (equal (nth 5 Info-complete-cache) Info-complete-nodes) 2693 (equal (nth 5 Info-complete-cache) Info-complete-nodes)
2694 (let ((prev (nth 3 Info-complete-cache))) 2694 (string-prefix-p (nth 3 Info-complete-cache) string) t)
2695 (eq t (compare-strings string 0 (length prev)
2696 prev 0 nil t))))
2697 ;; We can reuse the previous list. 2695 ;; We can reuse the previous list.
2698 (setq completions (nth 4 Info-complete-cache)) 2696 (setq completions (nth 4 Info-complete-cache))
2699 ;; The cache can't be used. 2697 ;; The cache can't be used.
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 7b252b4d46d..e7e08342b47 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -244,8 +244,7 @@ The result is a completion table which completes strings of the
244form (concat S1 S) in the same way as TABLE completes strings of 244form (concat S1 S) in the same way as TABLE completes strings of
245the form (concat S2 S)." 245the form (concat S2 S)."
246 (lambda (string pred action) 246 (lambda (string pred action)
247 (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil 247 (let* ((str (if (string-prefix-p s1 string completion-ignore-case)
248 completion-ignore-case))
249 (concat s2 (substring string (length s1))))) 248 (concat s2 (substring string (length s1)))))
250 (res (if str (complete-with-action action table str pred)))) 249 (res (if str (complete-with-action action table str pred))))
251 (when res 250 (when res
@@ -257,8 +256,7 @@ the form (concat S2 S)."
257 (+ beg (- (length s1) (length s2)))) 256 (+ beg (- (length s1) (length s2))))
258 . ,(and (eq (car-safe res) 'boundaries) (cddr res))))) 257 . ,(and (eq (car-safe res) 'boundaries) (cddr res)))))
259 ((stringp res) 258 ((stringp res)
260 (if (eq t (compare-strings res 0 (length s2) s2 nil nil 259 (if (string-prefix-p s2 string completion-ignore-case)
261 completion-ignore-case))
262 (concat s1 (substring res (length s2))))) 260 (concat s1 (substring res (length s2)))))
263 ((eq action t) 261 ((eq action t)
264 (let ((bounds (completion-boundaries str table pred ""))) 262 (let ((bounds (completion-boundaries str table pred "")))
diff --git a/lisp/subr.el b/lisp/subr.el
index 524b7954b7e..09a085288a5 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3677,12 +3677,14 @@ and replace a sub-expression, e.g.
3677 (setq matches (cons (substring string start l) matches)) ; leftover 3677 (setq matches (cons (substring string start l) matches)) ; leftover
3678 (apply #'concat (nreverse matches))))) 3678 (apply #'concat (nreverse matches)))))
3679 3679
3680(defun string-prefix-p (str1 str2 &optional ignore-case) 3680(defun string-prefix-p (prefix string &optional ignore-case)
3681 "Return non-nil if STR1 is a prefix of STR2. 3681 "Return non-nil if PREFIX is a prefix of STRING.
3682If IGNORE-CASE is non-nil, the comparison is done without paying attention 3682If IGNORE-CASE is non-nil, the comparison is done without paying attention
3683to case differences." 3683to case differences."
3684 (eq t (compare-strings str1 nil nil 3684 (let ((prefix-length (length prefix)))
3685 str2 0 (length str1) ignore-case))) 3685 (if (> prefix-length (length string)) nil
3686 (eq t (compare-strings prefix 0 prefix-length string
3687 0 prefix-length ignore-case)))))
3686 3688
3687(defun string-suffix-p (suffix string &optional ignore-case) 3689(defun string-suffix-p (suffix string &optional ignore-case)
3688 "Return non-nil if SUFFIX is a suffix of STRING. 3690 "Return non-nil if SUFFIX is a suffix of STRING.
diff --git a/src/ChangeLog b/src/ChangeLog
index 9f676a6518d..fc47fbc8978 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
12014-06-25 Dmitry Antipov <dmantipov@yandex.ru>
2
3 Do not allow out-of-range character position in Fcompare_strings.
4 * fns.c (validate_subarray): Add prototype.
5 (Fcompare_substring): Use validate_subarray to check ranges.
6 Adjust comment to mention that the semantics was changed. Also see
7 http://lists.gnu.org/archive/html/emacs-devel/2014-06/msg00447.html.
8
12014-06-24 Paul Eggert <eggert@cs.ucla.edu> 92014-06-24 Paul Eggert <eggert@cs.ucla.edu>
2 10
3 Be more consistent about the 'Qfoo' naming convention. 11 Be more consistent about the 'Qfoo' naming convention.
diff --git a/src/fns.c b/src/fns.c
index 5074ae3b41b..85e9f482fc1 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -50,7 +50,9 @@ static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper;
50static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; 50static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512;
51 51
52static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); 52static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object);
53 53static void validate_subarray (Lisp_Object, Lisp_Object, Lisp_Object,
54 ptrdiff_t, EMACS_INT *, EMACS_INT *);
55
54DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, 56DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
55 doc: /* Return the argument unchanged. */) 57 doc: /* Return the argument unchanged. */)
56 (Lisp_Object arg) 58 (Lisp_Object arg)
@@ -232,6 +234,7 @@ string STR1, compare the part between START1 (inclusive) and END1
232\(exclusive). If START1 is nil, it defaults to 0, the beginning of 234\(exclusive). If START1 is nil, it defaults to 0, the beginning of
233the string; if END1 is nil, it defaults to the length of the string. 235the string; if END1 is nil, it defaults to the length of the string.
234Likewise, in string STR2, compare the part between START2 and END2. 236Likewise, in string STR2, compare the part between START2 and END2.
237Like in `substring', negative values are counted from the end.
235 238
236The strings are compared by the numeric values of their characters. 239The strings are compared by the numeric values of their characters.
237For instance, STR1 is "less than" STR2 if its first differing 240For instance, STR1 is "less than" STR2 if its first differing
@@ -244,43 +247,25 @@ If string STR1 is less, the value is a negative number N;
244 - 1 - N is the number of characters that match at the beginning. 247 - 1 - N is the number of characters that match at the beginning.
245If string STR1 is greater, the value is a positive number N; 248If string STR1 is greater, the value is a positive number N;
246 N - 1 is the number of characters that match at the beginning. */) 249 N - 1 is the number of characters that match at the beginning. */)
247 (Lisp_Object str1, Lisp_Object start1, Lisp_Object end1, Lisp_Object str2, Lisp_Object start2, Lisp_Object end2, Lisp_Object ignore_case) 250 (Lisp_Object str1, Lisp_Object start1, Lisp_Object end1, Lisp_Object str2,
251 Lisp_Object start2, Lisp_Object end2, Lisp_Object ignore_case)
248{ 252{
249 register ptrdiff_t end1_char, end2_char; 253 EMACS_INT from1, to1, from2, to2;
250 register ptrdiff_t i1, i1_byte, i2, i2_byte; 254 ptrdiff_t i1, i1_byte, i2, i2_byte;
251 255
252 CHECK_STRING (str1); 256 CHECK_STRING (str1);
253 CHECK_STRING (str2); 257 CHECK_STRING (str2);
254 if (NILP (start1)) 258
255 start1 = make_number (0); 259 validate_subarray (str1, start1, end1, SCHARS (str1), &from1, &to1);
256 if (NILP (start2)) 260 validate_subarray (str2, start2, end2, SCHARS (str2), &from2, &to2);
257 start2 = make_number (0); 261
258 CHECK_NATNUM (start1); 262 i1 = from1;
259 CHECK_NATNUM (start2); 263 i2 = from2;
260 if (! NILP (end1))
261 CHECK_NATNUM (end1);
262 if (! NILP (end2))
263 CHECK_NATNUM (end2);
264
265 end1_char = SCHARS (str1);
266 if (! NILP (end1) && end1_char > XINT (end1))
267 end1_char = XINT (end1);
268 if (end1_char < XINT (start1))
269 args_out_of_range (str1, start1);
270
271 end2_char = SCHARS (str2);
272 if (! NILP (end2) && end2_char > XINT (end2))
273 end2_char = XINT (end2);
274 if (end2_char < XINT (start2))
275 args_out_of_range (str2, start2);
276
277 i1 = XINT (start1);
278 i2 = XINT (start2);
279 264
280 i1_byte = string_char_to_byte (str1, i1); 265 i1_byte = string_char_to_byte (str1, i1);
281 i2_byte = string_char_to_byte (str2, i2); 266 i2_byte = string_char_to_byte (str2, i2);
282 267
283 while (i1 < end1_char && i2 < end2_char) 268 while (i1 < to1 && i2 < to2)
284 { 269 {
285 /* When we find a mismatch, we must compare the 270 /* When we find a mismatch, we must compare the
286 characters, not just the bytes. */ 271 characters, not just the bytes. */
@@ -307,12 +292,8 @@ If string STR1 is greater, the value is a positive number N;
307 292
308 if (! NILP (ignore_case)) 293 if (! NILP (ignore_case))
309 { 294 {
310 Lisp_Object tem; 295 c1 = XINT (Fupcase (make_number (c1)));
311 296 c2 = XINT (Fupcase (make_number (c2)));
312 tem = Fupcase (make_number (c1));
313 c1 = XINT (tem);
314 tem = Fupcase (make_number (c2));
315 c2 = XINT (tem);
316 } 297 }
317 298
318 if (c1 == c2) 299 if (c1 == c2)
@@ -322,15 +303,15 @@ If string STR1 is greater, the value is a positive number N;
322 past the character that we are comparing; 303 past the character that we are comparing;
323 hence we don't add or subtract 1 here. */ 304 hence we don't add or subtract 1 here. */
324 if (c1 < c2) 305 if (c1 < c2)
325 return make_number (- i1 + XINT (start1)); 306 return make_number (- i1 + from1);
326 else 307 else
327 return make_number (i1 - XINT (start1)); 308 return make_number (i1 - from1);
328 } 309 }
329 310
330 if (i1 < end1_char) 311 if (i1 < to1)
331 return make_number (i1 - XINT (start1) + 1); 312 return make_number (i1 - from1 + 1);
332 if (i2 < end2_char) 313 if (i2 < to2)
333 return make_number (- i1 + XINT (start1) - 1); 314 return make_number (- i1 + from1 - 1);
334 315
335 return Qt; 316 return Qt;
336} 317}
diff --git a/test/ChangeLog b/test/ChangeLog
index 08492dd4c8f..3cb03b9f2f4 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,7 @@
12014-06-25 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * automated/fns-tests.el (fns-tests-compare-string): New test.
4
12014-06-24 Michael Albinus <michael.albinus@gmx.de> 52014-06-24 Michael Albinus <michael.albinus@gmx.de>
2 6
3 * automated/tramp-tests.el (tramp-test26-process-file): Extend test 7 * automated/tramp-tests.el (tramp-test26-process-file): Extend test
diff --git a/test/automated/fns-tests.el b/test/automated/fns-tests.el
index 21a9e4536af..461995b602e 100644
--- a/test/automated/fns-tests.el
+++ b/test/automated/fns-tests.el
@@ -69,3 +69,34 @@
69 (nreverse A) 69 (nreverse A)
70 (should (equal [nil nil nil nil nil t t t t t] (vconcat A))) 70 (should (equal [nil nil nil nil nil t t t t t] (vconcat A)))
71 (should (equal [t t t t t nil nil nil nil nil] (vconcat (nreverse A)))))) 71 (should (equal [t t t t t nil nil nil nil nil] (vconcat (nreverse A))))))
72
73(ert-deftest fns-tests-compare-strings ()
74 (should-error (compare-strings))
75 (should-error (compare-strings "xyzzy" "xyzzy"))
76 (should-error (compare-strings "xyzzy" 0 10 "zyxxy" 0 5))
77 (should-error (compare-strings "xyzzy" 0 5 "zyxxy" -1 2))
78 (should-error (compare-strings "xyzzy" 'foo nil "zyxxy" 0 1))
79 (should-error (compare-strings "xyzzy" 0 'foo "zyxxy" 2 3))
80 (should-error (compare-strings "xyzzy" 0 2 "zyxxy" 'foo 3))
81 (should-error (compare-strings "xyzzy" nil 3 "zyxxy" 4 'foo))
82 (should (compare-strings "" nil nil "" nil nil))
83 (should (compare-strings "" 0 0 "" 0 0))
84 (should (compare-strings "test" nil nil "test" nil nil))
85 (should (compare-strings "test" nil nil "test" nil nil t))
86 (should (compare-strings "test" nil nil "test" nil nil nil))
87 (should (compare-strings "Test" nil nil "test" nil nil t))
88 (should (= (compare-strings "Test" nil nil "test" nil nil) -1))
89 (should (= (compare-strings "Test" nil nil "test" nil nil) -1))
90 (should (= (compare-strings "test" nil nil "Test" nil nil) 1))
91 (should (= (compare-strings "foobaz" nil nil "barbaz" nil nil) 1))
92 (should (= (compare-strings "barbaz" nil nil "foobar" nil nil) -1))
93 (should (= (compare-strings "foobaz" nil nil "farbaz" nil nil) 2))
94 (should (= (compare-strings "farbaz" nil nil "foobar" nil nil) -2))
95 (should (compare-strings "abcxyz" 0 2 "abcprq" 0 2))
96 (should (compare-strings "abcxyz" 0 -3 "abcprq" 0 -3))
97 (should (= (compare-strings "abcxyz" 0 6 "abcprq" 0 6) 4))
98 (should (= (compare-strings "abcprq" 0 6 "abcxyz" 0 6) -4))
99 (should (compare-strings "xyzzy" -3 4 "azza" -3 3))
100 (should (compare-strings "こんにちはコンニチハ" nil nil "こんにちはコンニチハ" nil nil))
101 (should (= (compare-strings "んにちはコンニチハこ" nil nil "こんにちはコンニチハ" nil nil) 1))
102 (should (= (compare-strings "こんにちはコンニチハ" nil nil "んにちはコンニチハこ" nil nil) -1)))