From 8f1423946fd3ab9d5bca168de7fb12b9c397b034 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 17 Feb 2012 15:55:54 -0800 Subject: [PATCH] Fix a crash when using quotes due to wgettext thread safety issues. --- env_universal_common.cpp | 11 ---------- highlight.cpp | 2 +- history.cpp | 2 +- parse_util.cpp | 2 +- tokenizer.cpp | 22 +++++++++++++------- tokenizer.h | 7 +++++++ wutil.cpp | 45 ++++++++++++++++++++++------------------ wutil.h | 3 ++- 8 files changed, 52 insertions(+), 42 deletions(-) diff --git a/env_universal_common.cpp b/env_universal_common.cpp index 80fd1b1fa..9628b6309 100644 --- a/env_universal_common.cpp +++ b/env_universal_common.cpp @@ -382,17 +382,6 @@ void env_universal_common_init( void (*cb)(int type, const wchar_t *key, const w callback = cb; } -/** - Free both key and data -*/ -static void erase( void *key, - void *data ) -{ - free( (void *)key ); -// free( (void *)data );//data is allocated through new - delete data; -} - void env_universal_common_destroy() { diff --git a/highlight.cpp b/highlight.cpp index 2d4474782..059ccbfe1 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -557,7 +557,7 @@ static void tokenize( const wchar_t * const buff, int * const color, const int p color[i] = -1; tokenizer tok; - for( tok_init( &tok, buff, TOK_SHOW_COMMENTS ); + for( tok_init( &tok, buff, TOK_SHOW_COMMENTS | TOK_SQUASH_ERRORS ); tok_has_next( &tok ); tok_next( &tok ) ) { diff --git a/history.cpp b/history.cpp index 7d7f9196c..ad9abca27 100644 --- a/history.cpp +++ b/history.cpp @@ -776,7 +776,7 @@ void history_t::add_with_file_detection(const wcstring &str) path_list_t potential_paths; tokenizer tokenizer; - for( tok_init( &tokenizer, str.c_str(), 0 ); + for( tok_init( &tokenizer, str.c_str(), TOK_SQUASH_ERRORS ); tok_has_next( &tokenizer ); tok_next( &tokenizer ) ) { diff --git a/parse_util.cpp b/parse_util.cpp index 7b3781d55..e2fc9fcb7 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -523,7 +523,7 @@ void parse_util_token_extent( const wchar_t *buff, DIE_MEM(); } - for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED ); + for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS ); tok_has_next( &tok ); tok_next( &tok ) ) { diff --git a/tokenizer.cpp b/tokenizer.cpp index 0d2c90155..9ac832987 100644 --- a/tokenizer.cpp +++ b/tokenizer.cpp @@ -23,6 +23,8 @@ segments. #include "tokenizer.h" #include "common.h" +/* Wow what a hack */ +#define TOK_CALL_ERROR(t, e, x) do { tok_call_error((t), (e), (t)->squash_errors ? L"" : (x)); } while (0) /** Error string for unexpected end of string @@ -101,7 +103,7 @@ static int check_size( tokenizer *tok, size_t len ) /** Set the latest tokens string to be the specified error message */ -static void tok_error( tokenizer *tok, int error_type, const wchar_t *error_message ) +static void tok_call_error( tokenizer *tok, int error_type, const wchar_t *error_message ) { tok->last_type = TOK_ERROR; tok->error = error_type; @@ -124,6 +126,11 @@ int tok_get_error( tokenizer *tok ) void tok_init( tokenizer *tok, const wchar_t *b, int flags ) { + /* We can only generate error messages on the main thread due to wgettext() thread safety issues. */ + if (! (flags & TOK_SQUASH_ERRORS)) { + ASSERT_IS_MAIN_THREAD(); + } + CHECK( tok, ); memset( tok, 0, sizeof( tokenizer) ); @@ -133,6 +140,7 @@ void tok_init( tokenizer *tok, const wchar_t *b, int flags ) tok->accept_unfinished = !! (flags & TOK_ACCEPT_UNFINISHED); tok->show_comments = !! (flags & TOK_SHOW_COMMENTS); + tok->squash_errors = !! (flags & TOK_SQUASH_ERRORS); tok->has_next=1; tok->has_next = (*b != L'\0'); @@ -224,7 +232,7 @@ static void read_string( tokenizer *tok ) { if( (!tok->accept_unfinished) ) { - tok_error( tok, TOK_UNTERMINATED_ESCAPE, QUOTE_ERROR ); + TOK_CALL_ERROR( tok, TOK_UNTERMINATED_ESCAPE, QUOTE_ERROR ); return; } else @@ -290,7 +298,7 @@ static void read_string( tokenizer *tok ) if( (!tok->accept_unfinished) ) { - tok_error( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR ); + TOK_CALL_ERROR( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR ); return; } do_loop = 0; @@ -327,7 +335,7 @@ static void read_string( tokenizer *tok ) tok->buff += wcslen( tok->buff ); if( (!tok->accept_unfinished) ) { - tok_error( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR ); + TOK_CALL_ERROR( tok, TOK_UNTERMINATED_QUOTE, QUOTE_ERROR ); return; } do_loop = 0; @@ -381,7 +389,7 @@ static void read_string( tokenizer *tok ) if( (!tok->accept_unfinished) && (mode!=0) ) { - tok_error( tok, TOK_UNTERMINATED_SUBSHELL, PARAN_ERROR ); + TOK_CALL_ERROR( tok, TOK_UNTERMINATED_SUBSHELL, PARAN_ERROR ); return; } @@ -442,7 +450,7 @@ static void read_redirect( tokenizer *tok, int fd ) { if( fd == 0 ) { - tok_error( tok, TOK_OTHER, PIPE_ERROR ); + TOK_CALL_ERROR( tok, TOK_OTHER, PIPE_ERROR ); return; } check_size( tok, FD_STR_MAX_LEN ); @@ -459,7 +467,7 @@ static void read_redirect( tokenizer *tok, int fd ) } else { - tok_error( tok, TOK_OTHER, REDIRECT_ERROR); + TOK_CALL_ERROR( tok, TOK_OTHER, REDIRECT_ERROR); } if( !check_size( tok, 2 )) diff --git a/tokenizer.h b/tokenizer.h index c0c4034d4..731f49bf0 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -57,6 +57,10 @@ enum tokenizer_error */ #define TOK_SHOW_COMMENTS 2 +/** Flag telling the tokenizer to not generate error messages, which we need to do when tokenizing off of the main thread (since wgettext is not thread safe). +*/ +#define TOK_SQUASH_ERRORS 4 + /** The tokenizer struct. @@ -88,6 +92,9 @@ struct tokenizer wchar_t last_quote; /** Last error */ int error; + + /* Whether we are squashing errors */ + bool squash_errors; }; /** diff --git a/wutil.cpp b/wutil.cpp index 3621f13d7..c3dd80fc0 100644 --- a/wutil.cpp +++ b/wutil.cpp @@ -18,8 +18,10 @@ #include #include #include +#include #include + #if HAVE_LIBINTL_H #include #endif @@ -71,13 +73,6 @@ static char *wcs2str_buff=0; */ static size_t wcs2str_buff_count=0; -/** - For wgettext: Flag to tell whether the translation library has been initialized -*/ -static int wgettext_is_init = 0; - - - void wutil_init() { @@ -282,24 +277,25 @@ wcstring wbasename( const wcstring &path ) return result; } -/** - For wgettext: Internal init function. Automatically called when a translation is first requested. -*/ -static void wgettext_init() -{ - int i; - - wgettext_is_init = 1; - - for( i=0; i #include #include - +#include "common.h" /** @@ -134,6 +134,7 @@ std::wstring wbasename( const std::wstring &path); around gettext, like all other functions in this file. */ const wchar_t *wgettext( const wchar_t *in ); +wcstring wgettext2(const wcstring &in); /** Wide character version of getenv