~ chicken-core (chicken-5) 6b36695d94e0bd977e0d85d48438f621128e1101


commit 6b36695d94e0bd977e0d85d48438f621128e1101
Author:     Mario Domenech Goulart <mario.goulart@gmail.com>
AuthorDate: Fri Jun 27 17:43:38 2014 -0300
Commit:     Peter Bex <peter.bex@xs4all.nl>
CommitDate: Mon Jun 30 19:53:54 2014 +0200

    C_substring_copy: use C_memmove instead of C_memcpy
    
    memcpy will screw things up when given the src and dest strings'
    memory area overlap (e.g., the same string object is given as src and
    dest argument), and that can cause problems in some string-copy! use
    cases.
    
    Fixes #1135.
    
    Signed-off-by: Peter Bex <peter.bex@xs4all.nl>

diff --git a/NEWS b/NEWS
index a9ded9e5..c8ce4276 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@
   - Unit tcp now implicitly depends on ports instead of extras.
      This may break programs which don't use modules and forgot to
      require extras but use procedures from it.
+  - SRFI-13: fix string-copy! in cases source and destination strings'
+    memory areas overlap (#1135).
 
 - Unit lolevel:
   - Restore long-lost but still documented "vector-like?" procedure (#983)
diff --git a/chicken.h b/chicken.h
index 4a3c77ad..f5a103ee 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1260,9 +1260,9 @@ extern double trunc(double);
 #define C_i_char_greater_or_equal_p(x, y)  C_mk_bool(C_character_code(x) >= C_character_code(y))
 #define C_i_char_less_or_equal_p(x, y)  C_mk_bool(C_character_code(x) <= C_character_code(y))
 #define C_substring_copy(s1, s2, start1, end1, start2) \
-                                        (C_memcpy((C_char *)C_data_pointer(s2) + C_unfix(start2), \
-                                                  (C_char *)C_data_pointer(s1) + C_unfix(start1), \
-                                                  C_unfix(end1) - C_unfix(start1) ), C_SCHEME_UNDEFINED)
+                                        (C_memmove((C_char *)C_data_pointer(s2) + C_unfix(start2), \
+                                                   (C_char *)C_data_pointer(s1) + C_unfix(start1), \
+                                                   C_unfix(end1) - C_unfix(start1) ), C_SCHEME_UNDEFINED)
 #define C_substring_compare(s1, s2, start1, start2, len) \
                                         C_mk_bool(C_memcmp((C_char *)C_data_pointer(s1) + C_unfix(start1), \
                                                            (C_char *)C_data_pointer(s2) + C_unfix(start2), \
diff --git a/tests/srfi-13-tests.scm b/tests/srfi-13-tests.scm
index 1262b82d..8df378ac 100644
--- a/tests/srfi-13-tests.scm
+++ b/tests/srfi-13-tests.scm
@@ -115,6 +115,18 @@
        (let ((x (string-copy "abcdefg")))
          (string-copy! x 2 "ZABCDEFG" 3 6)
          x))
+
+;; From Guile.  Thanks to Mark H Weaver.
+(test "string-copy!: overlapping src and dest, moving right"
+      "aabce"
+      (let ((str (string-copy "abcde")))
+	(string-copy! str 1 str 0 3) str))
+
+(test "string-copy!: overlapping src and dest, moving left"
+      "bcdde"
+      (let ((str (string-copy "abcde")))
+	(string-copy! str 0 str 1 4) str))
+
 (test "string-take" "Pete S"  (string-take "Pete Szilagyi" 6))
 (test "string-take" ""        (string-take "Pete Szilagyi" 0))
 (test "string-take" "Pete Szilagyi" (string-take "Pete Szilagyi" 13))
Trap