From 3b8a4e56b0af8461f0f2f4c9469aba0e5a7536ba Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 29 Jan 2012 22:06:58 -0800 Subject: [PATCH] A bunch of work to move towards a sane memory model in job_t --- builtin.cpp | 20 +++++----- builtin.h | 2 +- builtin_complete.cpp | 3 +- builtin_jobs.cpp | 4 +- common.cpp | 6 +-- common.h | 2 +- complete.cpp | 3 +- event.cpp | 4 +- exec.cpp | 56 ++++++++++++++-------------- expand.cpp | 17 +++++---- parse_util.cpp | 6 +-- parse_util.h | 2 +- parser.cpp | 58 +++++++++++++---------------- parser.h | 6 +-- proc.cpp | 47 ++++++++++++----------- proc.h | 89 ++++++++++++++++++++++++++++++++++++++++---- 16 files changed, 195 insertions(+), 130 deletions(-) diff --git a/builtin.cpp b/builtin.cpp index 5d27d654b..fd3f77799 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -3014,7 +3014,7 @@ static int builtin_fg( parser_t &parser, wchar_t **argv ) _( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ), argv[0], pid, - j->command ); + j->command_cstr() ); builtin_print_help( parser, argv[0], sb_err ); j=0; } @@ -3028,7 +3028,7 @@ static int builtin_fg( parser_t &parser, wchar_t **argv ) sb_printf( sb_err, FG_MSG, j->job_id, - j->command ); + j->command_cstr() ); } else { @@ -3040,10 +3040,10 @@ static int builtin_fg( parser_t &parser, wchar_t **argv ) fwprintf( stderr, FG_MSG, j->job_id, - j->command ); + j->command_cstr() ); } - wchar_t *ft = tok_first( j->command ); + wchar_t *ft = tok_first( j->command_cstr() ); if( ft != 0 ) env_set( L"_", ft, ENV_EXPORT ); free(ft); @@ -3077,7 +3077,7 @@ static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name ) _( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ), L"bg", j->job_id, - j->command ); + j->command_cstr() ); builtin_print_help( parser, L"bg", sb_err ); return STATUS_BUILTIN_ERROR; } @@ -3086,7 +3086,7 @@ static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name ) sb_printf( sb_err, _(L"Send job %d '%ls' to background\n"), j->job_id, - j->command ); + j->command_cstr() ); } make_first( j ); job_set_flag( j, JOB_FOREGROUND, 0 ); @@ -3821,7 +3821,7 @@ int builtin_exists( wchar_t *cmd ) Return true if the specified builtin should handle it's own help, false otherwise. */ -static int internal_help( wchar_t *cmd ) +static int internal_help( const wchar_t *cmd ) { CHECK( cmd, 0 ); return contains( cmd, L"for", L"while", L"function", @@ -3829,15 +3829,15 @@ static int internal_help( wchar_t *cmd ) } -int builtin_run( parser_t &parser, wchar_t **argv, io_data_t *io ) +int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io ) { - int (*cmd)(parser_t &parser, wchar_t **argv)=0; + int (*cmd)(parser_t &parser, const wchar_t * const *argv)=0; real_io = io; CHECK( argv, STATUS_BUILTIN_ERROR ); CHECK( argv[0], STATUS_BUILTIN_ERROR ); - cmd = (int (*)(parser_t &parser, wchar_t **))hash_get( &builtin, argv[0] ); + cmd = (int (*)(parser_t &parser, const wchar_t * const*))hash_get( &builtin, argv[0] ); if( argv[1] != 0 && !internal_help(argv[0]) ) { diff --git a/builtin.h b/builtin.h index e90d24c0b..5ad27bf81 100644 --- a/builtin.h +++ b/builtin.h @@ -137,7 +137,7 @@ int builtin_exists( wchar_t *cmd ); \return the exit status of the builtin command */ -int builtin_run( parser_t &parser, wchar_t **argv, io_data_t *io ); +int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io ); /** Insert all builtin names into l. These are not copies of the strings and should not be freed after use. diff --git a/builtin_complete.cpp b/builtin_complete.cpp index 151739589..c35a6a830 100644 --- a/builtin_complete.cpp +++ b/builtin_complete.cpp @@ -542,7 +542,6 @@ static int builtin_complete( parser_t &parser, wchar_t **argv ) if( do_complete ) { std::vector comp; - int i; const wchar_t *prev_temporary_buffer = temporary_buffer; @@ -560,7 +559,7 @@ static int builtin_complete( parser_t &parser, wchar_t **argv ) complete2( do_complete, comp ); - for( i=0; i< comp.size() ; i++ ) + for( size_t i=0; i< comp.size() ; i++ ) { const completion_t &next = comp.at( i ); diff --git a/builtin_jobs.cpp b/builtin_jobs.cpp index 229a7cbeb..aacae8d22 100644 --- a/builtin_jobs.cpp +++ b/builtin_jobs.cpp @@ -99,7 +99,7 @@ static void builtin_jobs_print( job_t *j, int mode, int header ) sb_append( sb_out, job_is_stopped(j)?_(L"stopped"):_(L"running"), L"\t", - j->command, + j->command_cstr(), L"\n", NULL ); break; @@ -147,7 +147,7 @@ static void builtin_jobs_print( job_t *j, int mode, int header ) for( p=j->first_process; p; p=p->next ) { - sb_printf( sb_out, L"%ls\n", p->argv[0] ); + sb_printf( sb_out, L"%ls\n", p->argv0() ); } break; } diff --git a/common.cpp b/common.cpp index c5974d3e6..17e7348b4 100644 --- a/common.cpp +++ b/common.cpp @@ -159,14 +159,14 @@ wchar_t **list_to_char_arr( array_list_t *l ) wchar_t **completions_to_char_arr( std::vector &l ) { wchar_t ** res = (wchar_t **)malloc( sizeof(wchar_t *)*( l.size() + 1) ); - int i; + size_t i; if( res == 0 ) { DIE_MEM(); } for( i=0; i< l.size(); i++ ) { - res[i] = const_cast(l.at(i).completion.c_str()); + res[i] = wcsdup(l.at(i).completion.c_str()); } res[i]='\0'; return res; @@ -414,7 +414,7 @@ char *wcs2str_internal( const wchar_t *in, char *out ) return out; } -char **wcsv2strv( const wchar_t **in ) +char **wcsv2strv( const wchar_t * const *in ) { int count =0; int i; diff --git a/common.h b/common.h index 0fdfc4438..88fc4ca76 100644 --- a/common.h +++ b/common.h @@ -356,7 +356,7 @@ wcstring format_string(const wchar_t *format, ...); Returns a newly allocated wide character string array equivalent of the specified multibyte character string array */ -char **wcsv2strv( const wchar_t **in ); +char **wcsv2strv( const wchar_t * const *in ); /** Returns a newly allocated multibyte character string array equivalent of the specified wide character string array diff --git a/complete.cpp b/complete.cpp index 69ea413ae..ff523ee82 100644 --- a/complete.cpp +++ b/complete.cpp @@ -907,7 +907,6 @@ static void complete_strings( std::vector &comp_out, std::vector &possible_comp, int flags ) { - int i; wchar_t *wc, *tmp; tmp = expand_one( 0, @@ -918,7 +917,7 @@ static void complete_strings( std::vector &comp_out, wc = parse_util_unescape_wildcards( tmp ); free(tmp); - for( i=0; i< possible_comp.size(); i++ ) + for( size_t i=0; i< possible_comp.size(); i++ ) { wcstring temp = possible_comp.at( i ).completion; const wchar_t *next_str = temp.empty()?NULL:temp.c_str(); diff --git a/event.cpp b/event.cpp index b08856245..acb9af1fd 100644 --- a/event.cpp +++ b/event.cpp @@ -236,7 +236,7 @@ const wchar_t *event_get_desc( event_t *e ) { job_t *j = job_get_from_pid( -e->param1.pid ); if( j ) - sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command ); + sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command_cstr() ); else sb_printf( get_desc_buff, _(L"exit handler for job with process group %d"), -e->param1.pid ); } @@ -247,7 +247,7 @@ const wchar_t *event_get_desc( event_t *e ) { job_t *j = job_get( e->param1.job_id ); if( j ) - sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command ); + sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command_cstr() ); else sb_printf( get_desc_buff, _(L"exit handler for job with job id %d"), j->job_id ); diff --git a/exec.cpp b/exec.cpp index baf1e14d2..7897cafc3 100644 --- a/exec.cpp +++ b/exec.cpp @@ -467,7 +467,7 @@ static int setup_child_process( job_t *j, process_t *p ) call. Only use it in the execve error handler which calls exit right afterwards, anyway. */ -static wchar_t *get_interpreter( wchar_t *file ) +static wchar_t *get_interpreter( const wchar_t *file ) { string_buffer_t sb; FILE *fp = wfopen( file, "r" ); @@ -509,7 +509,7 @@ static void launch_process( process_t *p ) // debug( 1, L"exec '%ls'", p->argv[0] ); - char **argv = wcsv2strv( (const wchar_t **) p->argv); + char **argv = wcsv2strv(p->get_argv()); char **envv = env_export_arr( 0 ); execve ( wcs2str(p->actual_cmd), @@ -539,21 +539,21 @@ static void launch_process( process_t *p ) wchar_t **res; char **res_real; - while( p->argv[count] != 0 ) + while( p->argv(count) != 0 ) count++; - res = (wchar_t **)malloc( sizeof(wchar_t*)*(count+2)); - wchar_t sh_command[] = L"/bin/sh"; + res = (wchar_t **)malloc( sizeof(wchar_t*)*(count+3)); + const wchar_t *sh_command = L"/bin/sh"; - res[0] = sh_command; - res[1] = p->actual_cmd; + res[0] = wcsdup(sh_command); + res[1] = wcsdup(p->actual_cmd); - for( i=1; p->argv[i]; i++ ){ - res[i+1] = p->argv[i]; + for( i=1; p->argv(i) != NULL; i++ ){ + res[i+1] = wcsdup(p->argv(i)); } res[i+1] = 0; - p->argv = res; + p->set_argv(res); p->actual_cmd = sh_command; res_real = wcsv2strv( (const wchar_t **) res); @@ -841,9 +841,9 @@ static int set_child_group( job_t *j, process_t *p, int print_errors ) debug( 1, _( L"Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d" ), p->pid, - p->argv[0], + p->argv0(), j->job_id, - j->command, + j->command_cstr(), getpgid( p->pid), j->pgid ); @@ -863,7 +863,7 @@ static int set_child_group( job_t *j, process_t *p, int print_errors ) { debug( 1, _( L"Could not send job %d ('%ls') to foreground" ), j->job_id, - j->command ); + j->command_cstr() ); wperror( L"tcsetpgrp" ); res = -1; } @@ -978,7 +978,7 @@ void exec( parser_t &parser, job_t *j ) sigemptyset( &chldset ); sigaddset( &chldset, SIGCHLD ); - debug( 4, L"Exec job '%ls' with id %d", j->command, j->job_id ); + debug( 4, L"Exec job '%ls' with id %d", j->command_cstr(), j->job_id ); if( parser.block_io ) { @@ -1004,8 +1004,8 @@ void exec( parser_t &parser, job_t *j ) Input redirection - create a new gobetween process to take care of buffering */ - process_t *fake = (process_t *)halloc( j, sizeof(process_t) ); - fake->type = INTERNAL_BUFFER; + process_t *fake = new process_t(); + fake->type = INTERNAL_BUFFER; fake->pipe_write_fd = 1; j->first_process->pipe_read_fd = input_redirect->fd; fake->next = j->first_process; @@ -1187,31 +1187,33 @@ void exec( parser_t &parser, job_t *j ) */ signal_unblock(); - orig_def = function_get_definition( p->argv[0] ); + orig_def = function_get_definition( p->argv0() ); // function_get_named_arguments may trigger autoload, which deallocates the orig_def. // We should make function_get_definition return a wcstring (but how to handle NULL...) if (orig_def) orig_def = wcsdup(orig_def); - wcstring_list_t named_arguments = function_get_named_arguments( p->argv[0] ); - shadows = function_get_shadows( p->argv[0] ); + wcstring_list_t named_arguments = function_get_named_arguments( p->argv0() ); + shadows = function_get_shadows( p->argv0() ); signal_block(); if( orig_def ) { - def = (wchar_t *)halloc_register( j, const_cast(orig_def) ); + //def = (wchar_t *)halloc_register( j, const_cast(orig_def) ); + // PCA LEAKS + def = (wchar_t *)orig_def; } if( def == 0 ) { - debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] ); + debug( 0, _( L"Unknown function '%ls'" ), p->argv0() ); break; } parser.push_block( shadows?FUNCTION_CALL:FUNCTION_CALL_NO_SHADOW ); parser.current_block->param2.function_call_process = p; - parser.current_block->param1.function_call_name = (wchar_t *)halloc_register( parser.current_block, wcsdup( p->argv[0] ) ); + parser.current_block->param1.function_call_name = (wchar_t *)halloc_register( parser.current_block, wcsdup( p->argv0() ) ); /* @@ -1220,10 +1222,10 @@ void exec( parser_t &parser, job_t *j ) signals. */ signal_unblock(); - parse_util_set_argv( p->argv+1, named_arguments ); + parse_util_set_argv( p->get_argv()+1, named_arguments ); signal_block(); - parser.forbid_function( p->argv[0] ); + parser.forbid_function( p->argv0() ); if( p->next ) { @@ -1247,7 +1249,7 @@ void exec( parser_t &parser, job_t *j ) j->io = io_add( j->io, io_buffer ); } - internal_exec_helper( parser, p->argv[0], TOP, j->io ); + internal_exec_helper( parser, p->argv0(), TOP, j->io ); break; } @@ -1380,7 +1382,7 @@ void exec( parser_t &parser, job_t *j ) signal_unblock(); - p->status = builtin_run( parser, p->argv, j->io ); + p->status = builtin_run( parser, p->get_argv(), j->io ); builtin_out_redirect=old_out; builtin_err_redirect=old_err; @@ -1580,7 +1582,7 @@ void exec( parser_t &parser, job_t *j ) p->completed=1; if( p->next == 0 ) { - debug( 3, L"Set status of %ls to %d using short circut", j->command, p->status ); + debug( 3, L"Set status of %ls to %d using short circut", j->command_cstr(), p->status ); int status = p->status; proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status ); diff --git a/expand.cpp b/expand.cpp index 473f855a1..29d71865a 100644 --- a/expand.cpp +++ b/expand.cpp @@ -401,7 +401,7 @@ static int find_process( const wchar_t *proc, while ((j = jobs.next())) { wchar_t jid[16]; - if( j->command == 0 ) + if( j->command.size() == 0 ) continue; swprintf( jid, 16, L"%d", j->job_id ); @@ -414,7 +414,7 @@ static int find_process( const wchar_t *proc, sb_printf( &desc_buff, COMPLETE_JOB_DESC_VAL, - j->command ); + j->command_cstr() ); completion_allocate( out, jid+wcslen(proc), @@ -437,7 +437,7 @@ static int find_process( const wchar_t *proc, if( jid > 0 && !errno && !*end ) { j = job_get( jid ); - if( (j != 0) && (j->command != 0 ) ) + if( (j != 0) && (j->command_cstr() != 0 ) ) { { @@ -460,15 +460,15 @@ static int find_process( const wchar_t *proc, { int offset; - if( j->command == 0 ) + if( j->command_cstr() == 0 ) continue; - if( match_pid( j->command, proc, flags, &offset ) ) + if( match_pid( j->command_cstr(), proc, flags, &offset ) ) { if( flags & ACCEPT_INCOMPLETE ) { completion_allocate( out, - j->command + offset + wcslen(proc), + j->command_cstr() + offset + wcslen(proc), COMPLETE_JOB_DESC, 0 ); } @@ -493,7 +493,7 @@ static int find_process( const wchar_t *proc, while ((j = jobs.next())) { process_t *p; - if( j->command == 0 ) + if( j->command.size() == 0 ) continue; for( p=j->first_process; p; p=p->next ) { @@ -2621,7 +2621,8 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags ) // al_foreach( &l, &free ); // al_destroy( &l ); - halloc_register( context, one ); + if (context) + halloc_register( context, one ); return one; } diff --git a/parse_util.cpp b/parse_util.cpp index 90b609978..759c50e40 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -600,11 +600,11 @@ void parse_util_token_extent( const wchar_t *buff, } -void parse_util_set_argv( wchar_t **argv, const wcstring_list_t &named_arguments ) +void parse_util_set_argv( const wchar_t * const *argv, const wcstring_list_t &named_arguments ) { if( *argv ) { - wchar_t **arg; + const wchar_t * const *arg; string_buffer_t sb; sb_init( &sb ); @@ -627,7 +627,7 @@ void parse_util_set_argv( wchar_t **argv, const wcstring_list_t &named_arguments if( named_arguments.size() ) { - wchar_t **arg; + const wchar_t * const *arg; size_t i; for( i=0, arg=argv; i < named_arguments.size(); i++ ) diff --git a/parse_util.h b/parse_util.h index 28c4f003b..001313200 100644 --- a/parse_util.h +++ b/parse_util.h @@ -116,7 +116,7 @@ int parse_util_get_offset( wchar_t *buff, int line, int line_offset ); Set the argv environment variable to the specified null-terminated array of strings. */ -void parse_util_set_argv( wchar_t **argv, const wcstring_list_t &named_arguments ); +void parse_util_set_argv( const wchar_t * const *argv, const wcstring_list_t &named_arguments ); /** Make a duplicate of the specified string, unescape wildcard diff --git a/parser.cpp b/parser.cpp index 1f744e4c1..d7c847bf8 100644 --- a/parser.cpp +++ b/parser.cpp @@ -574,14 +574,9 @@ static const wchar_t *parser_find_end( const wchar_t * buff ) } -void parser_t::forbid_function( wchar_t *function ) +void parser_t::forbid_function( const wcstring &function ) { -/* - if( function ) - debug( 2, L"Forbid %ls\n", function ); -*/ - CHECK( function, ); - forbidden_function.push_back(wcstring(function)); + forbidden_function.push_back(function); } void parser_t::allow_function() @@ -937,14 +932,14 @@ void parser_t::stack_trace( block_t *b, string_buffer_t *buff) if( b->type == FUNCTION_CALL ) { - if( b->param2.function_call_process->argv[1] ) + if( b->param2.function_call_process->argv(1) ) { string_buffer_t tmp; sb_init( &tmp ); - for( i=1; b->param2.function_call_process->argv[i]; i++ ) + for( i=1; b->param2.function_call_process->argv(i); i++ ) { - sb_append( &tmp, i>1?L" ":L"", b->param2.function_call_process->argv[i], NULL ); + sb_append( &tmp, i>1?L" ":L"", b->param2.function_call_process->argv(i), NULL ); } sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff ); @@ -1202,7 +1197,7 @@ const wchar_t *parser_t::get_buffer() const } -int parser_t::is_help( wchar_t *s, int min_match ) const +int parser_t::is_help( const wchar_t *s, int min_match ) const { int len; @@ -1275,9 +1270,8 @@ void parser_t::parse_job_argument_list( process_t *p, return; } - if( !p->argv ) - halloc_register( j, p->argv = completions_to_char_arr( args ) ); - p->next = (process_t *)halloc( j, sizeof( process_t ) ); + p->set_argv(completions_to_char_arr(args)); + p->next = new process_t(); tok_next( tok ); @@ -1298,8 +1292,8 @@ void parser_t::parse_job_argument_list( process_t *p, case TOK_END: { - if( !p->argv ) - halloc_register( j, p->argv = completions_to_char_arr( args ) ); + if( !p->get_argv() ) + p->set_argv(completions_to_char_arr(args)); if( tok_has_next(tok)) tok_next(tok); @@ -1447,7 +1441,7 @@ void parser_t::parse_job_argument_list( process_t *p, { case TOK_STRING: { - target = (wchar_t *)expand_one( j, + target = expand_one( j, wcsdup( tok_last( tok ) ), no_exec ? EXPAND_SKIP_VARIABLES : 0); @@ -2047,7 +2041,7 @@ int parser_t::parse_job( process_t *p, error( SYNTAX_ERROR, tok_get_pos( tok ), UNKNOWN_BUILTIN_ERR_MSG, - args->at( args->size() -1 ) ); + args->back().completion.c_str() ); } } @@ -2147,8 +2141,8 @@ int parser_t::parse_job( process_t *p, { if( p->type == INTERNAL_BUILTIN && parser_keywords_skip_arguments( (wchar_t *)args->at( 0 ).completion.c_str() ) ) { - if( !p->argv ) - halloc_register( j, p->argv = completions_to_char_arr( *args ) ); + if( !p->get_argv() ) + p->set_argv(completions_to_char_arr( *args )); } else { @@ -2194,14 +2188,14 @@ void parser_t::skipped_exec( job_t * j ) { if( p->type == INTERNAL_BUILTIN ) { - if(( wcscmp( p->argv[0], L"for" )==0) || - ( wcscmp( p->argv[0], L"switch" )==0) || - ( wcscmp( p->argv[0], L"begin" )==0) || - ( wcscmp( p->argv[0], L"function" )==0)) + if(( wcscmp( p->argv0(), L"for" )==0) || + ( wcscmp( p->argv0(), L"switch" )==0) || + ( wcscmp( p->argv0(), L"begin" )==0) || + ( wcscmp( p->argv0(), L"function" )==0)) { this->push_block( FAKE ); } - else if( wcscmp( p->argv[0], L"end" )==0) + else if( wcscmp( p->argv0(), L"end" )==0) { if(!current_block->outer->skip ) { @@ -2210,7 +2204,7 @@ void parser_t::skipped_exec( job_t * j ) } parser_t::pop_block(); } - else if( wcscmp( p->argv[0], L"else" )==0) + else if( wcscmp( p->argv0(), L"else" )==0) { if( (current_block->type == IF ) && (current_block->param1.if_state != 0)) @@ -2219,7 +2213,7 @@ void parser_t::skipped_exec( job_t * j ) return; } } - else if( wcscmp( p->argv[0], L"case" )==0) + else if( wcscmp( p->argv0(), L"case" )==0) { if( (current_block->type == SWITCH ) ) { @@ -2287,12 +2281,12 @@ void parser_t::eval_job( tokenizer *tok ) } } - j->first_process = (process_t *)halloc( j, sizeof( process_t ) ); + j->first_process = new process_t(); job_begin_pos = tok_get_pos( tok ); if( parse_job( j->first_process, j, tok ) && - j->first_process->argv ) + j->first_process->get_argv() ) { if( job_start_pos < tok_get_pos( tok ) ) { @@ -2302,9 +2296,7 @@ void parser_t::eval_job( tokenizer *tok ) if( newline ) stop_pos = mini( stop_pos, newline - tok_string(tok) ); - j->command = halloc_wcsndup( j, - tok_string(tok)+start_pos, - stop_pos-start_pos ); + j->command = wcstring(tok_string(tok)+start_pos, stop_pos-start_pos); } else j->command = L""; @@ -2312,7 +2304,7 @@ void parser_t::eval_job( tokenizer *tok ) if( profile ) { t2 = get_time(); - profile_item->cmd = wcsdup( j->command ); + profile_item->cmd = wcsdup( j->command_cstr() ); profile_item->skipped=current_block->skip; } diff --git a/parser.h b/parser.h index 8c111e1e9..0d6cec3cd 100644 --- a/parser.h +++ b/parser.h @@ -236,7 +236,7 @@ class parser_t { int current_tokenizer_pos; /** List of called functions, used to help prevent infinite recursion */ - std::vector forbidden_function; + wcstring_list_t forbidden_function; /** String index where the current job started. */ int job_start_pos; @@ -395,7 +395,7 @@ class parser_t { inside of a conditional block. This is to remove some possibilities of infinite recursion. */ - void forbid_function( wchar_t *function ); + void forbid_function( const wcstring &function ); /** Undo last call to parser_forbid_function(). */ @@ -417,7 +417,7 @@ class parser_t { \param s the string to test \param min_match is the minimum number of characters that must match in a long style option, i.e. the longest common prefix between --help and any other option. If less than 3, 3 will be assumed. */ - int is_help( wchar_t *s, int min_match ) const; + int is_help( const wchar_t *s, int min_match ) const; /** Returns the file currently evaluated by the parser. This can be diff --git a/proc.cpp b/proc.cpp index 1ebc9a27d..07e82886d 100644 --- a/proc.cpp +++ b/proc.cpp @@ -178,7 +178,8 @@ void job_promote(job_t *job) void job_free( job_t * j ) { job_remove( j ); - halloc_free( j ); + j->~job_t(); + halloc_free( j ); } void proc_destroy() @@ -191,7 +192,7 @@ void proc_destroy() while( ! jobs.empty() ) { job_t *job = jobs.front(); - debug( 2, L"freeing leaked job %ls", job->command ); + debug( 2, L"freeing leaked job %ls", job->command_cstr() ); job_free( job ); } } @@ -209,11 +210,12 @@ int proc_get_last_status() job_t *job_create() { int free_id=1; - job_t *res; - + while( job_get( free_id ) != 0 ) free_id++; - res = new job_t(free_id); + + void *buff = halloc( 0, sizeof(job_t) ); + job_t *res = new (buff) job_t(free_id); job_list().push_front(res); job_set_flag( res, @@ -524,7 +526,7 @@ void job_handle_signal ( int signal, siginfo_t *info, void *con ) static void format_job_info( const job_t *j, const wchar_t *status ) { fwprintf (stdout, L"\r" ); - fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command, status); + fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_cstr(), status); fflush( stdout ); tputs(clr_eol,1,&writeb); fwprintf (stdout, L"\n" ); @@ -608,7 +610,7 @@ int job_reap( int interactive ) _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ), program_name, j->job_id, - j->command, + j->command_cstr(), sig2wcs(WTERMSIG(p->status)), signal_get_desc( WTERMSIG(p->status) ) ); else @@ -616,9 +618,9 @@ int job_reap( int interactive ) _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ), program_name, p->pid, - p->argv[0], + p->argv0(), j->job_id, - j->command, + j->command_cstr(), sig2wcs(WTERMSIG(p->status)), signal_get_desc( WTERMSIG(p->status) ) ); tputs(clr_eol,1,&writeb); @@ -851,7 +853,7 @@ static void read_try( job_t *j ) if( buff ) { - debug( 3, L"proc::read_try('%ls')\n", j->command ); + debug( 3, L"proc::read_try('%ls')\n", j->command_cstr() ); while(1) { char b[BUFFER_SIZE]; @@ -899,7 +901,7 @@ static int terminal_give_to_job( job_t *j, int cont ) debug( 1, _( L"Could not send job %d ('%ls') to foreground" ), j->job_id, - j->command ); + j->command_cstr() ); wperror( L"tcsetpgrp" ); return 0; } @@ -911,7 +913,7 @@ static int terminal_give_to_job( job_t *j, int cont ) debug( 1, _( L"Could not send job %d ('%ls') to foreground" ), j->job_id, - j->command ); + j->command_cstr() ); wperror( L"tcsetattr" ); return 0; } @@ -971,7 +973,7 @@ void job_continue (job_t *j, int cont) L"Continue job %d, gid %d (%ls), %ls, %ls", j->job_id, j->pgid, - j->command, + j->command_cstr(), job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED", is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" ); @@ -1169,9 +1171,6 @@ void proc_sanity_check() continue; - validate_pointer( j->command, - _( L"Job command" ), - 0 ); validate_pointer( j->first_process, _( L"Process list pointer" ), 0 ); @@ -1185,8 +1184,8 @@ void proc_sanity_check() { debug( 0, _( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"), - fg_job->command, - j->command ); + fg_job->command_cstr(), + j->command_cstr() ); sanity_lose(); } fg_job = j; @@ -1195,8 +1194,8 @@ void proc_sanity_check() p = j->first_process; while( p ) { - validate_pointer( p->argv, _( L"Process argument list" ), 0 ); - validate_pointer( p->argv[0], _( L"Process name" ), 0 ); + validate_pointer( p->get_argv(), _( L"Process argument list" ), 0 ); + validate_pointer( p->argv0(), _( L"Process name" ), 0 ); validate_pointer( p->next, _( L"Process list pointer" ), 1 ); validate_pointer( p->actual_cmd, _( L"Process command" ), 1 ); @@ -1204,8 +1203,8 @@ void proc_sanity_check() { debug( 0, _( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ), - j->command, - p->argv[0], + j->command_cstr(), + p->argv0(), p->stopped ); sanity_lose(); } @@ -1214,8 +1213,8 @@ void proc_sanity_check() { debug( 0, _( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ), - j->command, - p->argv[0], + j->command_cstr(), + p->argv0(), p->completed ); sanity_lose(); } diff --git a/proc.h b/proc.h index a76958e85..b8ba3b11e 100644 --- a/proc.h +++ b/proc.h @@ -19,6 +19,7 @@ #include "util.h" #include "io.h" +#include "common.h" /** The status code use when a command was not found @@ -126,19 +127,84 @@ enum */ class process_t { + private: + /** argv parameter for for execv, builtin_run, etc. This is allocated via malloc, and furthermore, each string within it is allocated via malloc as well . Null terminated. */ + wchar_t **argv_array; + + void free_argv(void) { + if (argv_array != NULL) { + for (size_t i = 0; argv_array[i] != NULL; i++) { + free(argv_array[i]); + } + free(argv_array); + } + } + public: + + process_t() : + argv_array(NULL), + type(0), + actual_cmd(NULL), + pid(0), + pipe_write_fd(0), + pipe_read_fd(0), + completed(0), + stopped(0), + status(0), + count_help_magic(0), + next(NULL) +#ifdef HAVE__PROC_SELF_STAT + ,last_time(), + unsigned long last_jiffies(0) +#endif + { + } + + ~process_t() + { + if (this->next != NULL) + delete this->next; + this->free_argv(); + } + /** Type of process. Can be one of \c EXTERNAL, \c INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK, INTERNAL_EXEC, or INTERNAL_BUFFER */ int type; + + + /** Sets argv */ + void set_argv(wchar_t **argv) { + free_argv(); - /** argv parameter for for execv, builtin_run, etc. */ - wchar_t **argv; +#if 0 + // argv must be a malloc'd array of malloc'd strings. This bit of nonsense below can help catch if someone doesn't pass us something from malloc. + if (argv) { + for (size_t i=0; argv[i]; i++) { + wchar_t *tmp = wcsdup(argv[i]); + free(argv[i]); + argv[i] = tmp; + } + } +#endif + + this->argv_array = argv; + } + + /** Returns argv */ + const wchar_t * const *get_argv(void) const { return argv_array; } + + /** Returns argv[0] */ + const wchar_t *argv0(void) const { return argv_array[0]; } + + /** Returns argv[idx] */ + const wchar_t *argv(size_t idx) const { return argv_array[idx]; } /** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC */ - wchar_t *actual_cmd; + const wchar_t *actual_cmd; /** process ID */ pid_t pid; @@ -161,8 +227,8 @@ class process_t /** Special flag to tell the evaluation function for count to print the help information */ int count_help_magic; - /** next process in pipeline */ - struct process_t *next; + /** Next process in pipeline. We own this and we are responsible for deleting it. */ + struct process_t *next; #ifdef HAVE__PROC_SELF_STAT /** Last time of cpu time check */ struct timeval last_time; @@ -239,7 +305,7 @@ class job_t public: job_t(int jobid) : - command(NULL), + command(), first_process(NULL), pgid(0), tmodes(), @@ -248,6 +314,11 @@ class job_t flags(0) { } + + ~job_t() { + if (first_process != NULL) + delete first_process; + } /** @@ -255,10 +326,12 @@ class job_t job. It is used for displaying messages about job status on the terminal. */ - const wchar_t *command; + wcstring command; + + const wchar_t *command_cstr() const { return command.c_str(); } /** - A linked list of all the processes in this job. + A linked list of all the processes in this job. We are responsible for deleting this when we are deallocated. */ process_t *first_process;