From af248ce2c17416ed33e9feb3d248347ee86f02e4 Mon Sep 17 00:00:00 2001 From: TingPing Date: Sat, 2 Nov 2013 02:05:55 -0400 Subject: [PATCH] Fix invalid timestamps crashing on Windows --- src/common/text.c | 11 ++---- src/common/util.c | 78 +++++++++++++++++++++++++++++++++++++++++++ src/common/util.h | 2 +- src/fe-gtk/setup.c | 9 ----- src/fe-text/fe-text.c | 2 +- 5 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/common/text.c b/src/common/text.c index 0b66c5fd..58d3b45c 100644 --- a/src/common/text.c +++ b/src/common/text.c @@ -542,7 +542,7 @@ log_create_pathname (char *servname, char *channame, char *netname) /* insert time/date */ now = time (NULL); tm = localtime (&now); - strftime (fnametime, sizeof (fnametime), fname, tm); + strftime_validated (fnametime, sizeof (fnametime), fname, tm); /* create final path/filename */ if (logmask_is_fullpath ()) @@ -649,14 +649,7 @@ get_stamp_str (char *fmt, time_t tim, char **ret) fmt = loc; } - len = strftime (dest, sizeof (dest), fmt, localtime (&tim)); -#ifdef WIN32 - if (!len) - { - /* use failsafe format until a correct one is specified */ - len = strftime (dest, sizeof (dest), "[%H:%M:%S]", localtime (&tim)); - } -#endif + len = strftime_validated (dest, sizeof (dest), fmt, localtime (&tim)); if (len) { if (prefs.utf8_locale) diff --git a/src/common/util.c b/src/common/util.c index cb6181c4..6e912169 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -2287,3 +2288,80 @@ challengeauth_response (char *username, char *password, char *challenge) return (char *) digest; } #endif + +/** +* \brief Wrapper around strftime for Windows +* +* Prevents crashing when using an invalid format by escaping them. +* +* Behaves the same as strftime with the addition that +* it returns 0 if the escaped format string is too large. +* +* Based upon work from znc-msvc project. +*/ +size_t +strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time) +{ +#ifndef WIN32 + return strftime (dest, destsize, format, time); +#else + char safe_format[64]; + const char *p = format; + int i = 0; + + if (strlen (format) >= sizeof(safe_format)) + return 0; + + memset (safe_format, 0, sizeof(safe_format)); + + while (*p) + { + if (*p == '%') + { + int has_hash = (*(p + 1) == '#'); + char c = *(p + (has_hash ? 2 : 1)); + + if (i >= sizeof (safe_format)) + return 0; + + switch (c) + { + case 'a': case 'A': case 'b': case 'B': case 'c': case 'd': case 'H': case 'I': case 'j': case 'm': case 'M': + case 'p': case 'S': case 'U': case 'w': case 'W': case 'x': case 'X': case 'y': case 'Y': case 'z': case 'Z': + case '%': + /* formatting code is fine */ + break; + default: + /* replace bad formatting code with itself, escaped, e.g. "%V" --> "%%V" */ + g_strlcat (safe_format, "%%", sizeof(safe_format)); + i += 2; + p++; + break; + } + + /* the current loop run will append % (and maybe #) and the next one will do the actual char. */ + if (has_hash) + { + safe_format[i] = *p; + p++; + i++; + } + if (c == '%') + { + safe_format[i] = *p; + p++; + i++; + } + } + + if (*p) + { + safe_format[i] = *p; + p++; + i++; + } + } + + return strftime (dest, destsize, safe_format, time); +#endif +} diff --git a/src/common/util.h b/src/common/util.h index 6b8d359c..0c54411b 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -83,5 +83,5 @@ char *encode_sasl_pass_plain (char *user, char *pass); char *encode_sasl_pass_blowfish (char *user, char *pass, char *data); char *encode_sasl_pass_aes (char *user, char *pass, char *data); char *challengeauth_response (char *username, char *password, char *challenge); - +size_t strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time); #endif diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index 2f52d5d9..a1a54ca4 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -2114,7 +2114,6 @@ setup_apply (struct hexchatprefs *pr) PangoFontDescription *old_desc; PangoFontDescription *new_desc; char buffer[4 * FONTNAMELEN + 1]; - time_t rawtime; #endif int new_pix = FALSE; int noapply = FALSE; @@ -2192,14 +2191,6 @@ setup_apply (struct hexchatprefs *pr) g_free (old_desc); g_free (new_desc); */ - - /* workaround for strftime differences between POSIX and MSVC */ - time (&rawtime); - - if (!strftime (buffer, sizeof (buffer), prefs.hex_stamp_text_format, localtime (&rawtime)) || !strftime (buffer, sizeof (buffer), prefs.hex_stamp_log_format, localtime (&rawtime))) - { - fe_message (_("Invalid time stamp format! See the strftime MSDN article for details."), FE_MSG_ERROR); - } #endif if (prefs.hex_irc_real_name[0] == 0) diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c index 6f197916..76f93d8d 100644 --- a/src/fe-text/fe-text.c +++ b/src/fe-text/fe-text.c @@ -121,7 +121,7 @@ fe_new_window (struct session *sess, int focus) static int get_stamp_str (time_t tim, char *dest, int size) { - return strftime (dest, size, prefs.hex_stamp_text_format, localtime (&tim)); + return strftime_validated (dest, size, prefs.hex_stamp_text_format, localtime (&tim)); } static int