[PATCH] Fix potentially broken white space truncation on certain Windows versions

Lubomir I. Ivanov neolit123 at gmail.com
Thu Mar 7 11:16:31 PST 2013


From: "Lubomir I. Ivanov" <neolit123 at gmail.com>

Testing the Planner in Subsurface on a Windows XP SP3 installation,
shows corrupted UTF-8 strings in the case of Cyrillic locales, but
possibly others as well. Instead limited to the Planner, this affects
the entire application.

After some examination it appears that <ctype>'s isspace() in MSVC
on the tested version of Windows is broken for some UTF-8 characters,
after enabling the user locale using: setlocale(LC_ALL, "");

For example, characters such as the Cyrillic capital "BE" are defined as:
0xD091, where isspace() for the first byte returns 0x08, which is the
bytemask for C1_SPACE and the character is treated as space.
After a byte is treated as space, it is usually discarded from a UTF-8
character/string, where if only one byte left, corrupting the entire
string.

In Subsurface, usages of string trimming are present in multiple
locations, so to make this work try to use GLib's g_ascii_isspace(),
which is a locale agnostic version of isspace().

Affected versions of Windows could be everything up to XP SP3,
but not apparently Vista.

Reported-by: Sergey Starosek <sergey.starosek at gmail.com>
Signed-off-by: Lubomir I. Ivanov <neolit123 at gmail.com>
---

an updated version of a previous patch with the same title, but using
g_ascii_isspace() instead of g_unichar_isspace().

---
 info.c      |  6 +++---
 parse-xml.c |  8 ++++----
 planner.c   | 24 ++++++++++++------------
 save-xml.c  |  4 ++--
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/info.c b/info.c
index 0517eac..4a4b41c 100644
--- a/info.c
+++ b/info.c
@@ -48,7 +48,7 @@ static int text_changed(const char *old, const char *new)
 static const char *skip_space(const char *str)
 {
 	if (str) {
-		while (isspace(*str))
+		while (g_ascii_isspace(*str))
 			str++;
 		if (!*str)
 			str = NULL;
@@ -82,7 +82,7 @@ static char *get_combo_box_entry_text(GtkComboBox *combo_box, char **textp, cons
 			return NULL;
 
 	new = get_active_text(combo_box);
-	while (isspace(*new))
+	while (g_ascii_isspace(*new))
 		new++;
 	/* If the master string didn't change, don't change other dives either! */
 	if (!text_changed(master,new))
@@ -724,7 +724,7 @@ static gboolean gps_entry_change_cb(GtkEntry *gps, GdkEvent *event, gpointer use
 	}
 
 	/* Otherwise, check if it's all empty.. */
-	while (isspace(*string))
+	while (g_ascii_isspace(*string))
 		string++;
 	location_update.set_by_hand = !!*string;
 
diff --git a/parse-xml.c b/parse-xml.c
index 80a1244..4661321 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -386,7 +386,7 @@ static void percent(char *buffer, void *_fraction)
 	case FLOAT:
 		/* Turn fractions into percent unless explicit.. */
 		if (val <= 1.0) {
-			while (isspace(*end))
+			while (g_ascii_isspace(*end))
 				end++;
 			if (*end != '%')
 				val *= 100;
@@ -437,10 +437,10 @@ static void utf8_string(char *buffer, void *_res)
 {
 	int size;
 	char *res;
-	while (isspace(*buffer))
+	while (g_ascii_isspace(*buffer))
 		buffer++;
 	size = strlen(buffer);
-	while (size && isspace(buffer[size-1]))
+	while (size && g_ascii_isspace(buffer[size-1]))
 		size--;
 	if (!size)
 		return;
@@ -926,7 +926,7 @@ static degrees_t parse_degrees(char *buf, char **end)
 	int sign = 1, decimals = 6, value = 0;
 	degrees_t ret;
 
-	while (isspace(*buf))
+	while (g_ascii_isspace(*buf))
 		buf++;
 	switch (*buf) {
 	case '-':
diff --git a/planner.c b/planner.c
index d5a733e..b11cda1 100644
--- a/planner.c
+++ b/planner.c
@@ -789,7 +789,7 @@ static int validate_gas(const char *text, int *o2_p, int *he_p)
 	if (!text)
 		return 0;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 
 	if (!*text)
@@ -806,7 +806,7 @@ static int validate_gas(const char *text, int *o2_p, int *he_p)
 	}
 
 	/* We don't want any extra crud */
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 	if (*text)
 		return 0;
@@ -829,14 +829,14 @@ static int validate_time(const char *text, int *sec_p, int *rel_p)
 	if (!text)
 		return 0;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 
 	rel = 0;
 	if (*text == '+') {
 		rel = 1;
 		text++;
-		while (isspace(*text))
+		while (g_ascii_isspace(*text))
 			text++;
 	}
 
@@ -873,7 +873,7 @@ static int validate_time(const char *text, int *sec_p, int *rel_p)
 	}
 
 	/* Maybe we should accept 'min' at the end? */
-	if (isspace(*text))
+	if (g_ascii_isspace(*text))
 		text++;
 	if (*text)
 		return 0;
@@ -894,7 +894,7 @@ static int validate_depth(const char *text, int *mm_p)
 	if (depth < 0)
 		return 0;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 
 	imperial = get_units()->length == FEET;
@@ -905,7 +905,7 @@ static int validate_depth(const char *text, int *mm_p)
 		imperial = 1;
 		text += 2;
 	}
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 	if (*text)
 		return 0;
@@ -933,10 +933,10 @@ static int validate_po2(const char *text, int *mbar_po2)
 	if (po2 < 0)
 		return 0;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 	if (*text)
 		return 0;
@@ -956,7 +956,7 @@ static int validate_volume(const char *text, int *sac)
 	if (volume < 0)
 		return 0;
 
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 
 	imperial = get_units()->volume == CUFT;
@@ -967,11 +967,11 @@ static int validate_volume(const char *text, int *sac)
 		imperial = 1;
 		text += 4;
 	}
-	while (isspace(*text) || *text == '/')
+	while (g_ascii_isspace(*text) || *text == '/')
 		text++;
 	if (!strncasecmp(text, _("min"), 3))
 		text += 3;
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 	if (*text)
 		return 0;
diff --git a/save-xml.c b/save-xml.c
index a23fb10..7ae71dd 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -125,12 +125,12 @@ static void show_utf8(FILE *f, const char *text, const char *pre, const char *po
 
 	if (!text)
 		return;
-	while (isspace(*text))
+	while (g_ascii_isspace(*text))
 		text++;
 	len = strlen(text);
 	if (!len)
 		return;
-	while (len && isspace(text[len-1]))
+	while (len && g_ascii_isspace(text[len-1]))
 		len--;
 	/* FIXME! Quoting! */
 	fputs(pre, f);
-- 
1.7.11.msysgit.0



More information about the subsurface mailing list