Index: libcfa/src/containers/string_res.cfa
===================================================================
--- libcfa/src/containers/string_res.cfa	(revision 6f7aff39a23cd54f3b8131e9f26394eb753dce9c)
+++ libcfa/src/containers/string_res.cfa	(revision fe18b46d7a80d743842002e3565a3f0e9fc6a0a4)
@@ -258,4 +258,17 @@
 }
 
+// private ctor (not in header): use specified heap (ignore ambient) and copy chars in
+void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
+    (Handle){ heap };
+    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
+    Handle.lnth = rhslnth;
+    (s.shareEditSet_owns_ulink){ false };
+    for ( int i = 0; i < rhslnth; i += 1 ) {		// copy characters
+        Handle.s[i] = rhs[i];
+    } // for
+    s.shareEditSet_prev = &s;
+    s.shareEditSet_next = &s;
+}
+
 // General copy constructor
 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
@@ -263,15 +276,24 @@
     verify( start <= end && end <= s2.Handle.lnth );
 
-    if (s2.Handle.ulink == ambient_string_sharectx->activeHeap) {
-        // same heap: allow overlap
+    if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
+        // crossing heaps (including private): copy eagerly
+        eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
+        verify(s.shareEditSet_prev == &s);
+        verify(s.shareEditSet_next == &s);
+    } else {
         (s.Handle){};
         s.Handle.s = s2.Handle.s + start;
         s.Handle.lnth = end - start;
-        s.Handle.ulink = ambient_string_sharectx->activeHeap;
-        (s.shareEditSet_owns_ulink){ false };
+        s.Handle.ulink = s2.Handle.ulink;
+
         AddThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
         // ^ bug?  skip others at early point in string
-    
+
         if (mode == COPY_VALUE) {
+            verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
+            // requested logical copy in same heap: defer copy until write
+
+            (s.shareEditSet_owns_ulink){ false };
+
             // make s alone in its shareEditSet
             s.shareEditSet_prev = &s;
@@ -279,4 +301,7 @@
         } else {
             verify( mode == SHARE_EDITS );
+            // sharing edits with source forces same heap as source (ignore context)
+
+            (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
 
             // s2 is logically const but not implementation const
@@ -289,10 +314,4 @@
             s.shareEditSet_prev->shareEditSet_next = &s;
         }
-    } else {
-        // crossing heaps: eager copy
-        assert( mode == COPY_VALUE && "need to solidify context-crossing rules for requesting shared edits");
-        eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
-        verify(s.shareEditSet_prev == &s);
-        verify(s.shareEditSet_next == &s);
     }
 }
@@ -400,7 +419,7 @@
             // growing: copy from old to new
             char * dest = VbyteAlloc( *this.Handle.ulink, editSetLength );
-            char *destCursor = dest;        memcpy(destCursor, prefixStartOrig, prefixLen);
-            destCursor += prefixLen;        memcpy(destCursor, buffer         , bsize    );
-            destCursor += this.Handle.lnth; memcpy(destCursor, suffixStartOrig, suffixLen);
+            char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
+            destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
+            destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
             assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
                 dest,
@@ -437,17 +456,4 @@
         // `this` occurs in the middle of it, to be replaced
         // build up the new text in `pasting`
-
-        // super private string ctor: ignore ambient context
-        void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
-            (Handle){ heap };
-            Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
-            Handle.lnth = rhslnth;
-            (s.shareEditSet_owns_ulink){ false };
-            for ( int i = 0; i < rhslnth; i += 1 ) {		// copy characters
-                Handle.s[i] = rhs[i];
-            } // for
-            s.shareEditSet_prev = &s;
-            s.shareEditSet_next = &s;
-        }
 
         string_res pasting = {
@@ -538,6 +544,7 @@
             VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
         } else {					// copy the two parts
-            char * str1oldBuf = str1.Handle.s;
-            str1.Handle.s = VbyteAlloc( *str1.Handle.ulink, clnth );
+            char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
+            char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
+            str1.Handle.s = str1newBuf;
             ByteCopy( str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth);
         } // if
