Crash on startup (due to broken locale)
Since (I think, but it is a long time ago) 1.4.3-ish, pan crashed on start-up. Reading the notes on 1.4.5, I had hopes it would be fixed, but alas, nope.
So I decided to find out some more.
$ git lg
* 22c743d (HEAD -> master, origin/master, origin/HEAD) Update Swedish translation
$ cat build_it.sh
#!/bin/sh
set -e -u -x
CCFLAGS=-g CXXFLAGS=-g ./autogen.sh --prefix=$HOME/pan2/installed
make
make install
After running the script, starting the installed pan ~/pan2/installed/bin/pan
with gdb
.
It crashed as normal, high-lights:
Thread 1 "pan" received signal SIGSEGV, Segmentation fault.
0x00007ffff417b845 in __strstr_sse2 () from /lib64/libc.so.6
#0 0x00007ffff417b845 in __strstr_sse2 () at /lib64/libc.so.6
#1 0x00000000007a0987 in EvolutionDateMaker::e_strftime_fix_am_pm(char*, unsigned long, char const*, tm const*) const (this=0x7fffffffa570, s=0x7fffffffa3f0 "0\244\377\377\377\177", max=100, fmt=0x0, tm=0x7fffffffa460) at e-util.cc:145
#2 0x00000000007a0ab3 in EvolutionDateMaker::e_utf8_strftime_fix_am_pm(char*, unsigned long, char const*, tm const*) const (this=0x7fffffffa570, s=0x7fffffffa3f0 "0\244\377\377\377\177", max=100, locale_fmt=0x0, tm=0x7fffffffa460) at e-util.cc:170
#3 0x00000000007a1262 in EvolutionDateMaker::get_date_string(long) const (this=0x7fffffffa570, then_time=1536904627) at e-util.cc:319
#4 0x0000000000667954 in pan::HeaderPane::create_row(EvolutionDateMaker const&, pan::Article const*) (this=0x1086c00, e=..., a=0x1c19e88) at header-pane.cc:429
#5 0x000000000066969d in pan::HeaderPane::on_tree_change(pan::Data::ArticleTree::Diffs const&) (this=0x1086c00, diffs=...) at header-pane.cc:831
... (omitted)
So it crashes inside libc
. The fmt=0x0
argument doesn't look good, and indeed it's not:
145: if (am_pm_are_defined_in_locale || (!strstr(fmt,"%p") && !strstr(fmt,"%P")))
170: size_t ret = e_strftime_fix_am_pm(s, max, locale_fmt, tm);
319: e_utf8_strftime_fix_am_pm (buf, sizeof(buf), locale_this_week, &then_tm);
(lines may be off wrt the git version, as I added some debug lines I'll show below)
The locale_this_week
is assigned in the constructor, and sure enough, it becomes NULL
. Debug code:
diff --git a/pan/general/e-util.cc b/pan/general/e-util.cc
index af5ccd0..887a130 100644
--- a/pan/general/e-util.cc
+++ b/pan/general/e-util.cc
@@ -205,14 +205,61 @@ EvolutionDateMaker :: set_current_time (time_t now)
}
}
+static const char *safe_str(GError *e)
+{
+ return e ? e->message : "<null>";
+}
+
+static void pfmt(const char *t)
+{
+ if (!t) {
+ printf("fmt=<null>\n");
+ return;
+ }
+ printf("fmt:");
+ const char *s = t;
+ while (*s) {
+ printf(" %02x", *s);
+ s++;
+ }
+ printf(" \"");
+ s = t;
+ while (*s) {
+ if (*s >= 32 && *s <= 126) printf("%c", *s);
+ else printf(".");
+ s++;
+ }
+ printf("\"\n");
+}
+
EvolutionDateMaker :: EvolutionDateMaker (time_t now)
{
// build the locale strings
- locale_recent = g_locale_from_utf8 (_("%l∶%M %p"), -1, NULL, NULL, NULL);
- locale_today = g_locale_from_utf8 (_("Today %l∶%M %p"), -1, NULL, NULL, NULL);
- locale_this_week = g_locale_from_utf8 (_("%a %l∶%M %p"), -1, NULL, NULL, NULL);
- locale_this_year = g_locale_from_utf8 (_("%b %d %l∶%M %p"), -1, NULL, NULL, NULL);
- locale_old = g_locale_from_utf8 (_("%b %d %Y"), -1, NULL, NULL, NULL);
+ GError *e = NULL;
+ locale_recent = g_locale_from_utf8 (_("%l∶%M %p"), -1, NULL, NULL, &e);
+ pfmt(_("%l∶%M %p"));
+ printf("locale_recent = %p %s\n", locale_recent, safe_str(e));
+ if (e) g_error_free(e); e = NULL;
+
+ locale_today = g_locale_from_utf8 (_("Today %l∶%M %p"), -1, NULL, NULL, &e);
+ pfmt(_("Today %l∶%M %p"));
+ printf("locale_today = %p %s\n", locale_today, safe_str(e));
+ if (e) g_error_free(e); e = NULL;
+
+ locale_this_week = g_locale_from_utf8 (_("%a %l∶%M %p"), -1, NULL, NULL, &e);
+ pfmt(_("%a %l∶%M %p"));
+ printf("locale_this_week = %p %s\n", locale_this_week, safe_str(e));
+ if (e) g_error_free(e); e = NULL;
+
+ locale_this_year = g_locale_from_utf8 (_("%b %d %l∶%M %p"), -1, NULL, NULL, &e);
+ pfmt(_("%b %d %l∶%M %p"));
+ printf("locale_this_year = %p %s\n", locale_this_year, safe_str(e));
+ if (e) g_error_free(e); e = NULL;
+
+ locale_old = g_locale_from_utf8 (_("%b %d %Y"), -1, NULL, NULL, &e);
+ pfmt(_("%b %d %Y"));
+ printf("locale_old = %p %s\n", locale_old, safe_str(e));
+ if (e) g_error_free(e); e = NULL;
// set the current time
set_current_time (now);
Rebuilding with the patch, and running again gives:
fmt: 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%l...%M %p"
locale_recent = (nil) Invalid byte sequence in conversion input
fmt: 54 6f 64 61 79 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "Today %l...%M %p"
locale_today = (nil) Invalid byte sequence in conversion input
fmt: 25 61 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%a %l...%M %p"
locale_this_week = (nil) Invalid byte sequence in conversion input
fmt: 25 62 20 25 64 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%b %d %l...%M %p"
locale_this_year = (nil) Invalid byte sequence in conversion input
fmt: 25 62 20 25 64 20 25 59 "%b %d %Y"
locale_old = 0x13f0290 <null>
fmt: 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%l...%M %p"
locale_recent = (nil) Invalid byte sequence in conversion input
fmt: 54 6f 64 61 79 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "Today %l...%M %p"
locale_today = (nil) Invalid byte sequence in conversion input
fmt: 25 61 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%a %l...%M %p"
locale_this_week = (nil) Invalid byte sequence in conversion input
fmt: 25 62 20 25 64 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%b %d %l...%M %p"
locale_this_year = (nil) Invalid byte sequence in conversion input
fmt: 25 62 20 25 64 20 25 59 "%b %d %Y"
locale_old = 0x113d470 <null>
Note locale_this_week = (nil) Invalid byte sequence in conversion input
, ie utf8 conversion is reporting an error and returns NULL
. The output of pfmt(_("%a %l∶%M %p"));
is at the line above: fmt: 25 61 20 25 6c ffffffe2 ffffff88 ffffffb6 25 4d 20 25 70 "%a %l...%M %p"
. There are 3 weird values in the utf8 string which may be the cause, given my quite broken locale (note that local_old
does get converted correctly).
$ locale
LANG=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME=en_DK.UTF-8
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
I haven't touched my locale for years, no idea why it's this strange.
Fixing the locale with by all locale variables from env, and setting export LANG=en_US.utf8
fixes the problem.
In bugzilla, bugs https://bugzilla.gnome.org/show_bug.cgi?id=796482 and https://bugzilla.gnome.org/show_bug.cgi?id=791898 look like they also crash in the strftime libc function.
Something seems to attach too much to having a valid locale, but I don't know where. Hope it is useful.