diff --git a/ChangeLog b/ChangeLog
index 63b82c321728136a124452a1b2067f94bdceaa56..982f91ba032289c9f54d5e041e72111672eeb7b3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -170,6 +170,11 @@ CVS code -
   control_rep(), control_mbrep()
 	- Assert that the multibyte character passed in is a control
 	  character if it's valid. (DLR)
+	- If crep is an invalid multibyte sequence, copy Unicode 0xFFFD
+	  (Replacement Character) into it using strncpy() instead of
+	  assigning the former to it.  This avoids segfaults when freeing
+	  crep later, since it's supposed to be dynamically allocated.
+	  (DLR)
   mbrep()
 	- New function, the equivalent of control_mbrep() for non-control
 	  characters. (DLR)
diff --git a/src/chars.c b/src/chars.c
index e51547bc8dacffd3c1781d760677e970e4ab64fc..945a9f53091a7657474a9e2040e7a7d90d1111ec 100644
--- a/src/chars.c
+++ b/src/chars.c
@@ -213,7 +213,10 @@ wchar_t control_wrep(wchar_t wc)
 #endif
 
 /* c is a multibyte control character.  It displays as ^@, ^?, or ^[ch],
- * where ch is (c + 64).  We return that multibyte character. */
+ * where ch is (c + 64).  We return that multibyte character.  If crep
+ * is an invalid multibyte sequence, it will be replaced with Unicode
+ * 0xFFFD (Replacement Character), so it should be dynamically allocated
+ * and able to hold MB_CUR_MAX single-byte characters. */
 char *control_mbrep(const char *c, char *crep, int *crep_len)
 {
     assert(c != NULL && crep != NULL && crep_len != NULL);
@@ -224,8 +227,8 @@ char *control_mbrep(const char *c, char *crep, int *crep_len)
 
 	if (mbtowc(&wc, c, MB_CUR_MAX) < 0) {
 	    mbtowc(NULL, NULL, 0);
-	    crep = (char *)bad_mbchar;
 	    *crep_len = bad_mbchar_len;
+	    strncpy(crep, bad_mbchar, *crep_len);
 	} else {
 	    *crep_len = wctomb(crep, control_wrep(wc));
 
@@ -246,7 +249,10 @@ char *control_mbrep(const char *c, char *crep, int *crep_len)
 }
 
 /* c is a multibyte non-control character.  We return that multibyte
- * character. */
+ * character.  If crep is an invalid multibyte sequence, it will be
+ * replaced with Unicode 0xFFFD (Replacement Character), so it should be
+ * dynamically allocated and able to hold MB_CUR_MAX single-byte
+ * characters. */
 char *mbrep(const char *c, char *crep, int *crep_len)
 {
     assert(c != NULL && crep != NULL && crep_len != NULL);
@@ -258,8 +264,8 @@ char *mbrep(const char *c, char *crep, int *crep_len)
 	/* Reject invalid Unicode characters. */
 	if (mbtowc(&wc, c, MB_CUR_MAX) < 0 || !is_valid_unicode(wc)) {
 	    mbtowc(NULL, NULL, 0);
-	    crep = (char *)bad_mbchar;
 	    *crep_len = bad_mbchar_len;
+	    strncpy(crep, bad_mbchar, *crep_len);
 	} else {
 	    *crep_len = wctomb(crep, wc);