mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Fix a crash when using quotes due to wgettext thread safety issues.
This commit is contained in:
parent
51da4856e2
commit
8f1423946f
8 changed files with 52 additions and 42 deletions
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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 ) )
|
||||
{
|
||||
|
|
|
@ -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 ) )
|
||||
{
|
||||
|
|
|
@ -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 ) )
|
||||
{
|
||||
|
|
|
@ -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 ))
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
45
wutil.cpp
45
wutil.cpp
|
@ -18,8 +18,10 @@
|
|||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
#if HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#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<BUFF_COUNT; i++ )
|
||||
/* Really init wgettext */
|
||||
static void wgettext_really_init() {
|
||||
for( size_t i=0; i<BUFF_COUNT; i++ )
|
||||
{
|
||||
sb_init( &buff[i] );
|
||||
}
|
||||
|
||||
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
||||
textdomain( PACKAGE_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
For wgettext: Internal init function. Automatically called when a translation is first requested.
|
||||
*/
|
||||
static void wgettext_init_if_necessary()
|
||||
{
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&once, wgettext_really_init);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
For wgettext: Wide to narrow character conversion. Internal implementation that
|
||||
|
@ -322,11 +318,12 @@ static char *wgettext_wcs2str( const wchar_t *in )
|
|||
|
||||
const wchar_t *wgettext( const wchar_t *in )
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
if( !in )
|
||||
return in;
|
||||
|
||||
if( !wgettext_is_init )
|
||||
wgettext_init();
|
||||
wgettext_init_if_necessary();
|
||||
|
||||
char *mbs_in = wgettext_wcs2str( in );
|
||||
char *out = gettext( mbs_in );
|
||||
|
@ -341,6 +338,14 @@ const wchar_t *wgettext( const wchar_t *in )
|
|||
return wres;
|
||||
}
|
||||
|
||||
wcstring wgettext2(const wcstring &in) {
|
||||
wgettext_init_if_necessary();
|
||||
std::string mbs_in = wcs2string(in);
|
||||
char *out = gettext( mbs_in.c_str() );
|
||||
wcstring result = format_string(L"%s", out);
|
||||
return result;
|
||||
}
|
||||
|
||||
const wchar_t *wgetenv( const wchar_t *name )
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
|
3
wutil.h
3
wutil.h
|
@ -15,7 +15,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
|
|
Loading…
Reference in a new issue