r23598 - gnucash/trunk/src/backend/xml - Bug 710824 - GnuCash should sanitise UTF-8 before serialising files

John Ralls jralls at code.gnucash.org
Sun Dec 22 17:32:04 EST 2013


Author: jralls
Date: 2013-12-22 17:32:04 -0500 (Sun, 22 Dec 2013)
New Revision: 23598
Trac: http://svn.gnucash.org/trac/changeset/23598

Added:
   gnucash/trunk/src/backend/xml/gnc-xml-helper.c
Modified:
   gnucash/trunk/src/backend/xml/Makefile.am
   gnucash/trunk/src/backend/xml/gnc-recurrence-xml-v2.c
   gnucash/trunk/src/backend/xml/gnc-schedxaction-xml-v2.c
   gnucash/trunk/src/backend/xml/gnc-transaction-xml-v2.c
   gnucash/trunk/src/backend/xml/gnc-xml-helper.h
   gnucash/trunk/src/backend/xml/io-gncxml-v2.c
   gnucash/trunk/src/backend/xml/sixtp-dom-generators.c
   gnucash/trunk/src/backend/xml/sixtp-to-dom-parser.c
   gnucash/trunk/src/backend/xml/test/Makefile.am
   gnucash/trunk/src/backend/xml/test/test-string-converters.c
Log:
Bug 710824 - GnuCash should sanitise UTF-8 before serialising files

to avoid writing broken unparseable XML.
This checks for both bad UTF8 and for invalid control characters
that libxml2 doesn't convert to entities.

Modified: gnucash/trunk/src/backend/xml/Makefile.am
===================================================================
--- gnucash/trunk/src/backend/xml/Makefile.am	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/Makefile.am	2013-12-22 22:32:04 UTC (rev 23598)
@@ -39,6 +39,7 @@
   gnc-tax-table-xml-v2.c \
   gnc-transaction-xml-v2.c \
   gnc-vendor-xml-v2.c \
+  gnc-xml-helper.c \
   io-example-account.c \
   io-gncxml-gen.c \
   io-gncxml-v1.c \

Modified: gnucash/trunk/src/backend/xml/gnc-recurrence-xml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-recurrence-xml-v2.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/gnc-recurrence-xml-v2.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -136,7 +136,7 @@
     WeekendAdjust wadj;
 
     n = xmlNewNode(NULL, BAD_CAST tag);
-    xmlSetProp(n, BAD_CAST "version", BAD_CAST recurrence_version_string );
+    xmlSetProp(n, BAD_CAST "version", BAD_CAST recurrence_version_string);
     xmlAddChild(n, guint_to_dom_tree(recurrence_mult,
                                      recurrenceGetMultiplier(r)));
     pt = recurrenceGetPeriodType(r);

Modified: gnucash/trunk/src/backend/xml/gnc-schedxaction-xml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-schedxaction-xml-v2.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/gnc-schedxaction-xml-v2.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -85,11 +85,12 @@
     gint        instCount;
     const GncGUID        *templ_acc_guid;
     gboolean allow_2_2_incompat = TRUE;
+    gchar *name = g_strdup (xaccSchedXactionGetName(sx));
 
     templ_acc_guid = xaccAccountGetGUID(sx->template_acct);
 
     /* FIXME: this should be the same as the def in io-gncxml-v2.c */
-    ret = xmlNewNode( NULL, BAD_CAST GNC_SCHEDXACTION_TAG );
+    ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
 
     if (allow_2_2_incompat)
         xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
@@ -100,7 +101,8 @@
                  guid_to_dom_tree(SX_ID,
                                   xaccSchedXactionGetGUID(sx)) );
 
-    xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, BAD_CAST xaccSchedXactionGetName(sx) );
+    xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
+    g_free (name);
 
     if (allow_2_2_incompat)
     {

Modified: gnucash/trunk/src/backend/xml/gnc-transaction-xml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-transaction-xml-v2.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/gnc-transaction-xml-v2.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -74,21 +74,25 @@
     xmlAddChild(ret, guid_to_dom_tree("split:id", xaccSplitGetGUID(spl)));
 
     {
-        const char *memo = xaccSplitGetMemo(spl);
+        char *memo = g_strdup (xaccSplitGetMemo(spl));
 
         if (memo && g_strcmp0(memo, "") != 0)
         {
-            xmlNewTextChild(ret, NULL, BAD_CAST "split:memo", (xmlChar*)memo);
+            xmlNewTextChild(ret, NULL, BAD_CAST "split:memo",
+			    checked_char_cast (memo));
         }
+	g_free (memo);
     }
 
     {
-        const char *action = xaccSplitGetAction(spl);
+        char *action = g_strdup (xaccSplitGetAction(spl));
 
         if (action && g_strcmp0(action, "") != 0)
         {
-            xmlNewTextChild(ret, NULL, BAD_CAST "split:action", (xmlChar*)action);
+            xmlNewTextChild(ret, NULL, BAD_CAST "split:action",
+			    checked_char_cast (action));
         }
+	g_free (action);
     }
 
     {
@@ -97,7 +101,8 @@
         tmp[0] = xaccSplitGetReconcile(spl);
         tmp[1] = '\0';
 
-        xmlNewTextChild(ret, NULL, BAD_CAST "split:reconciled-state", (xmlChar*)tmp);
+        xmlNewTextChild(ret, NULL, BAD_CAST "split:reconciled-state",
+			BAD_CAST tmp);
     }
 
     add_timespec(ret, "split:reconcile-date",
@@ -153,31 +158,37 @@
 gnc_transaction_dom_tree_create(Transaction *trn)
 {
     xmlNodePtr ret;
+    gchar *str = NULL;
 
     ret = xmlNewNode(NULL, BAD_CAST "gnc:transaction");
 
-    xmlSetProp(ret, BAD_CAST "version", BAD_CAST transaction_version_string);
+    xmlSetProp(ret, BAD_CAST "version",
+	       BAD_CAST transaction_version_string);
 
     xmlAddChild(ret, guid_to_dom_tree("trn:id", xaccTransGetGUID(trn)));
 
     xmlAddChild(ret, commodity_ref_to_dom_tree("trn:currency",
                 xaccTransGetCurrency(trn)));
-
-    if (xaccTransGetNum(trn) && (g_strcmp0(xaccTransGetNum(trn), "") != 0))
+    str = g_strdup (xaccTransGetNum(trn));
+    if (str && (g_strcmp0(str, "") != 0))
     {
-        xmlNewTextChild(ret, NULL, BAD_CAST "trn:num", (xmlChar*)xaccTransGetNum(trn));
+        xmlNewTextChild(ret, NULL, BAD_CAST "trn:num",
+			checked_char_cast (str));
     }
+    g_free (str);
 
     add_timespec(ret, "trn:date-posted", xaccTransRetDatePostedTS(trn), TRUE);
 
     add_timespec(ret, "trn:date-entered",
                  xaccTransRetDateEnteredTS(trn), TRUE);
 
-    if (xaccTransGetDescription(trn))
+    str = g_strdup (xaccTransGetDescription(trn));
+    if (str)
     {
         xmlNewTextChild(ret, NULL, BAD_CAST "trn:description",
-                        (xmlChar*)xaccTransGetDescription(trn));
+                        checked_char_cast (str));
     }
+    g_free (str);
 
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree("trn:slots",

Copied: gnucash/trunk/src/backend/xml/gnc-xml-helper.c (from rev 23597, gnucash/trunk/src/backend/xml/gnc-xml-helper.h)
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-xml-helper.c	                        (rev 0)
+++ gnucash/trunk/src/backend/xml/gnc-xml-helper.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -0,0 +1,50 @@
+/********************************************************************\
+ * gnc-xml-helper.h -- api for xml helpers                          *
+ *                                                                  *
+ * Copyright (C) 2001 James LewisMoss <dres at debian.org>             *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+#include <glib.h>
+#include "gnc-xml-helper.h"
+
+xmlChar*
+checked_char_cast (gchar *val)
+{
+    const int length = -1; /* Assumes val is null-terminated */
+    gchar *end;
+    if (val == NULL) return NULL;
+    /* Replace any invalid UTF-8 characters with a sequence of '?' */
+    while (!g_utf8_validate (val, length, (const gchar**)(&end)))
+        *end = '?';
+    /* Replace any invalid (for XML) control characters (everything < 0x20
+     * except \n, \t, and \r) with '?'. Technically we should replace
+     * these with a numeric entity, but that will blow up the libxml
+     * functions that expect raw text. It seems unlikely that anyone
+     * would use intentionally use one of these characters anyway.
+     */
+
+     for (end = val; *end; ++end)
+	if (*end > 0 && *end < 0x20 && *end != 0x09 &&
+	    *end != 0x0a && *end != 0x0d)
+	    *end = '?';
+    return (xmlChar*)(val);
+}
+

Modified: gnucash/trunk/src/backend/xml/gnc-xml-helper.h
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-xml-helper.h	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/gnc-xml-helper.h	2013-12-22 22:32:04 UTC (rev 23598)
@@ -42,5 +42,6 @@
 #    define xmlAttrPropertyValue children
 #  endif /* ifndef xmlAttrPropertyValue */
 
+xmlChar* checked_char_cast (gchar *val);
 
 #endif /* _GNC_XML_HELPER_H_ */

Modified: gnucash/trunk/src/backend/xml/io-gncxml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/io-gncxml-v2.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/io-gncxml-v2.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -887,7 +887,7 @@
     gboolean success = TRUE;
 
     va_start(ap, out);
-    type = va_arg(ap, char *);
+    type = g_strdup (va_arg(ap, char *));
 
     while (success && type)
     {
@@ -907,9 +907,10 @@
              * This is invalid xml because the namespace isn't
              * declared in the tag itself. This should be changed to
              * 'type' at some point. */
-            xmlSetProp(node, BAD_CAST "cd:type", BAD_CAST type);
-            xmlNodeAddContent(node, BAD_CAST val);
+            xmlSetProp(node, BAD_CAST "cd:type", checked_char_cast (type));
+            xmlNodeAddContent(node, checked_char_cast (val));
             g_free(val);
+	    g_free (type);
 
             xmlElemDump(out, NULL, node);
             xmlFreeNode(node);
@@ -1141,7 +1142,7 @@
        increment the progress bar as we go. */
        
     if (fprintf( out, "<%s version=\"%s\">\n", parent->name, 
-                 xmlGetProp(parent, (xmlChar*) "version")) < 0)
+                 xmlGetProp(parent, BAD_CAST "version")) < 0)
         return FALSE;
         
     /* We create our own output buffer so we can call xmlNodeDumpOutput to get

Modified: gnucash/trunk/src/backend/xml/sixtp-dom-generators.c
===================================================================
--- gnucash/trunk/src/backend/xml/sixtp-dom-generators.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/sixtp-dom-generators.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -44,12 +44,13 @@
 text_to_dom_tree(const char *tag, const char *str)
 {
     xmlNodePtr result;
-
+    gchar *newstr = g_strdup (str);
     g_return_val_if_fail(tag, NULL);
     g_return_val_if_fail(str, NULL);
     result = xmlNewNode(NULL, BAD_CAST tag);
     g_return_val_if_fail(result, NULL);
-    xmlNodeAddContent(result, BAD_CAST str);
+    xmlNodeAddContent(result, checked_char_cast (newstr));
+    g_free (newstr);
     return result;
 }
 
@@ -105,6 +106,7 @@
 commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c)
 {
     xmlNodePtr ret;
+    gchar *namespace, *mnemonic;
 
     g_return_val_if_fail(c, NULL);
 
@@ -114,10 +116,14 @@
     {
         return NULL;
     }
-
-    xmlNewTextChild(ret, NULL, BAD_CAST "cmdty:space", BAD_CAST gnc_commodity_get_namespace_compat(c));
-    xmlNewTextChild(ret, NULL, BAD_CAST "cmdty:id", BAD_CAST gnc_commodity_get_mnemonic(c));
-
+    namespace = g_strdup (gnc_commodity_get_namespace_compat(c));
+    mnemonic = g_strdup (gnc_commodity_get_mnemonic(c));
+    xmlNewTextChild(ret, NULL, BAD_CAST "cmdty:space",
+		    checked_char_cast (namespace));
+    xmlNewTextChild(ret, NULL, BAD_CAST "cmdty:id",
+		    checked_char_cast (mnemonic));
+    g_free (namespace);
+    g_free (mnemonic);
     return ret;
 }
 
@@ -162,14 +168,16 @@
 
     ret = xmlNewNode(NULL, BAD_CAST tag);
 
-    xmlNewTextChild(ret, NULL, BAD_CAST "ts:date", BAD_CAST date_str);
+    xmlNewTextChild(ret, NULL, BAD_CAST "ts:date",
+		    checked_char_cast (date_str));
 
     if (spec->tv_nsec > 0)
     {
         ns_str = timespec_nsec_to_string(spec);
         if (ns_str)
         {
-            xmlNewTextChild(ret, NULL, BAD_CAST "ts:ns", BAD_CAST ns_str);
+            xmlNewTextChild(ret, NULL, BAD_CAST "ts:ns",
+			    checked_char_cast (ns_str));
         }
     }
 
@@ -195,7 +203,7 @@
 
     ret = xmlNewNode(NULL, BAD_CAST tag);
 
-    xmlNewTextChild(ret, NULL, BAD_CAST "gdate", BAD_CAST date_str);
+    xmlNewTextChild(ret, NULL, BAD_CAST "gdate", checked_char_cast (date_str));
 
     g_free(date_str);
 
@@ -215,7 +223,7 @@
 
     ret = xmlNewNode(NULL, BAD_CAST tag);
 
-    xmlNodeAddContent(ret, BAD_CAST numstr);
+    xmlNodeAddContent(ret, checked_char_cast (numstr));
 
     g_free(numstr);
 
@@ -242,9 +250,12 @@
 static void
 add_text_to_node(xmlNodePtr node, gchar *type, gchar *val)
 {
-    xmlSetProp(node, BAD_CAST "type", BAD_CAST type);
-    xmlNodeSetContent(node, BAD_CAST val);
-    g_free(val);
+    gchar *newtype = g_strdup (type);
+    gchar *newval = g_strdup (val);
+    xmlSetProp(node, BAD_CAST "type", checked_char_cast (type));
+    xmlNodeSetContent(node, checked_char_cast (val));
+    g_free (newtype);
+    g_free(newval);
 }
 
 
@@ -256,13 +267,17 @@
 add_kvp_value_node(xmlNodePtr node, gchar *tag, kvp_value* val)
 {
     xmlNodePtr val_node;
-    gchar *tmp_str1;
     kvp_value_t kvp_type;
 
     kvp_type = kvp_value_get_type(val);
 
     if (kvp_type == KVP_TYPE_STRING)
-        val_node = xmlNewTextChild(node, NULL, BAD_CAST tag, BAD_CAST kvp_value_get_string(val));
+    {
+	gchar *newstr = g_strdup (kvp_value_get_string(val));
+        val_node = xmlNewTextChild(node, NULL, BAD_CAST tag,
+				   checked_char_cast (newstr));
+	g_free (newstr);
+    }
     else if (kvp_type == KVP_TYPE_TIMESPEC)
         val_node = NULL;
     else if (kvp_type == KVP_TYPE_GDATE)
@@ -312,11 +327,12 @@
     case KVP_TYPE_BINARY:
     {
         guint64 size;
+	gchar *tmp_str1;
         void *binary_data = kvp_value_get_binary(val, &size);
         xmlSetProp(val_node, BAD_CAST "type", BAD_CAST "binary");
         g_return_if_fail(binary_data);
         tmp_str1 = binary_to_string(binary_data, size);
-        xmlNodeSetContent(val_node, BAD_CAST tmp_str1);
+        xmlNodeSetContent(val_node, checked_char_cast (tmp_str1));
         g_free(tmp_str1);
     }
     break;
@@ -356,11 +372,12 @@
 {
     xmlNodePtr slot_node;
     xmlNodePtr node = (xmlNodePtr)data;
-
+    gchar *newkey = g_strdup ((gchar*)key);
     slot_node = xmlNewChild(node, NULL, BAD_CAST "slot", NULL);
 
-    xmlNewTextChild(slot_node, NULL, BAD_CAST "slot:key", (xmlChar*)key);
-
+    xmlNewTextChild(slot_node, NULL, BAD_CAST "slot:key",
+		    checked_char_cast (newkey));
+    g_free (newkey);
     add_kvp_value_node(slot_node, "slot:value", (kvp_value*)value);
 }
 

Modified: gnucash/trunk/src/backend/xml/sixtp-to-dom-parser.c
===================================================================
--- gnucash/trunk/src/backend/xml/sixtp-to-dom-parser.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/sixtp-to-dom-parser.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -63,7 +63,12 @@
     {
         while (*atptr != 0)
         {
-            xmlSetProp(thing, BAD_CAST atptr[0], BAD_CAST atptr[1]);
+	    gchar *attr0 = g_strdup (atptr[0]);
+	    gchar *attr1 = g_strdup (atptr[1]);
+            xmlSetProp(thing, checked_char_cast (attr0),
+		       checked_char_cast (attr1));
+	    g_free (attr0);
+	    g_free (attr1);
             atptr += 2;
         }
     }
@@ -88,7 +93,10 @@
 {
     if (length > 0)
     {
-        xmlNodeAddContentLen((xmlNodePtr)parent_data, BAD_CAST text, length);
+	gchar *newtext = g_strdup (text);
+        xmlNodeAddContentLen((xmlNodePtr)parent_data,
+			     checked_char_cast (newtext), length);
+	g_free (newtext);
     }
     return TRUE;
 }

Modified: gnucash/trunk/src/backend/xml/test/Makefile.am
===================================================================
--- gnucash/trunk/src/backend/xml/test/Makefile.am	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/test/Makefile.am	2013-12-22 22:32:04 UTC (rev 23598)
@@ -8,6 +8,7 @@
   ${top_srcdir}/src/backend/xml/sixtp.c \
   ${top_srcdir}/src/backend/xml/sixtp-stack.c \
   ${top_srcdir}/src/backend/xml/sixtp-to-dom-parser.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-date-converting.c
 
 test_dom_converters1_SOURCES = \
@@ -17,6 +18,7 @@
   ${top_srcdir}/src/backend/xml/sixtp.c \
   ${top_srcdir}/src/backend/xml/sixtp-stack.c \
   ${top_srcdir}/src/backend/xml/sixtp-to-dom-parser.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-dom-converters1.c
 
 test_kvp_frames_SOURCES = \
@@ -26,6 +28,7 @@
   ${top_srcdir}/src/backend/xml/sixtp.c \
   ${top_srcdir}/src/backend/xml/sixtp-stack.c \
   ${top_srcdir}/src/backend/xml/sixtp-to-dom-parser.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-kvp-frames.c
 
 # the xml backend is now a GModule - this test does
@@ -53,6 +56,7 @@
   ${top_srcdir}/src/backend/xml/gnc-commodity-xml-v2.c \
   ${top_srcdir}/src/backend/xml/gnc-book-xml-v2.c \
   ${top_srcdir}/src/backend/xml/gnc-pricedb-xml-v2.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-load-example-account.c
 
 test_string_converters_SOURCES = \
@@ -62,6 +66,7 @@
   ${top_srcdir}/src/backend/xml/sixtp.c \
   ${top_srcdir}/src/backend/xml/sixtp-stack.c \
   ${top_srcdir}/src/backend/xml/sixtp-to-dom-parser.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-string-converters.c
 
 test_xml_account_SOURCES = \
@@ -84,6 +89,7 @@
   ${top_srcdir}/src/backend/xml/gnc-budget-xml-v2.c \
   ${top_srcdir}/src/backend/xml/io-gncxml-v2.c \
   ${top_srcdir}/src/backend/xml/io-utils.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-xml-account.c
 
 test_xml_commodity_SOURCES = \
@@ -106,6 +112,7 @@
   ${top_srcdir}/src/backend/xml/gnc-budget-xml-v2.c \
   ${top_srcdir}/src/backend/xml/io-gncxml-v2.c \
   ${top_srcdir}/src/backend/xml/io-utils.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-xml-commodity.c
 
 test_xml_pricedb_SOURCES = \
@@ -128,6 +135,7 @@
   ${top_srcdir}/src/backend/xml/gnc-budget-xml-v2.c \
   ${top_srcdir}/src/backend/xml/io-gncxml-v2.c \
   ${top_srcdir}/src/backend/xml/io-utils.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-xml-pricedb.c
 
 test_xml_transaction_SOURCES = \
@@ -150,6 +158,7 @@
   ${top_srcdir}/src/backend/xml/gnc-pricedb-xml-v2.c \
   ${top_srcdir}/src/backend/xml/io-gncxml-v2.c \
   ${top_srcdir}/src/backend/xml/io-utils.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-xml-transaction.c
 
 test_xml2_is_file_SOURCES = \
@@ -172,6 +181,7 @@
   ${top_srcdir}/src/backend/xml/io-gncxml-gen.c \
   ${top_srcdir}/src/backend/xml/io-gncxml-v2.c \
   ${top_srcdir}/src/backend/xml/io-utils.c \
+  ${top_srcdir}/src/backend/xml/gnc-xml-helper.c \
   test-xml2-is-file.c
 
 TESTS = \

Modified: gnucash/trunk/src/backend/xml/test/test-string-converters.c
===================================================================
--- gnucash/trunk/src/backend/xml/test/test-string-converters.c	2013-12-22 22:13:42 UTC (rev 23597)
+++ gnucash/trunk/src/backend/xml/test/test-string-converters.c	2013-12-22 22:32:04 UTC (rev 23598)
@@ -103,6 +103,20 @@
     }
 }
 
+static void
+test_bad_string (void)
+{
+    gchar *badstr = "foo\abar";
+    gchar *sanitized = "foo?bar";
+    gchar *backout;
+    xmlNodePtr test_node = text_to_dom_tree ("test-string", badstr);
+
+    backout = dom_tree_to_text (test_node);
+    do_test_args (g_strcmp0 (backout, sanitized) == 0,
+		  "string sanitizing", __FILE__, __LINE__,
+		  "with string %s", badstr);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -110,6 +124,7 @@
     test_binary();
     fflush(stdout);
     test_string_converters();
+    test_bad_string ();
     fflush(stdout);
     print_test_results();
     exit(get_rv());



More information about the gnucash-changes mailing list