bash: Update to 4.2.53

Includes the latest bunch of security fixes

Signed-off-by: Marcel Denia <naoir@gmx.net>
This commit is contained in:
Marcel Denia 2014-10-06 09:27:22 +02:00
parent 4280780f6c
commit d3397ab01d
8 changed files with 469 additions and 247 deletions

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=bash
PKG_VERSION:=4.2
PKG_RELEASE:=4
PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/bash

View File

@ -4,7 +4,7 @@
Bash-Release: 4.2
Patch-ID: bash42-049
Bug-Reported-by: Tavis Ormandy <taviso () cmpxchg8b com>
Bug-Reported-by: Tavis Ormandy <taviso@cmpxchg8b.com>
Bug-Reference-ID:
Bug-Reference-URL: http://twitter.com/taviso/statuses/514887394294652929
@ -26,22 +26,6 @@ Patch (apply with `patch -p0'):
current_token = '\n'; /* XXX */
last_read_token = '\n';
token_to_read = '\n';
--- a/y.tab.c
+++ b/y.tab.c
@@ -5160,6 +5160,8 @@ reset_parser ()
FREE (word_desc_to_read);
word_desc_to_read = (WORD_DESC *)NULL;
+ eol_ungetc_lookahead = 0;
+
current_token = '\n'; /* XXX */
last_read_token = '\n';
token_to_read = '\n';
@@ -8321,4 +8323,3 @@ set_line_mbstate ()
}
}
#endif /* HANDLE_MULTIBYTE */
-
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@

View File

@ -0,0 +1,172 @@
BASH PATCH REPORT
=================
Bash-Release: 4.2
Patch-ID: bash42-050
Bug-Reported-by: Florian Weimer <fweimer@redhat.com>
Bug-Reference-ID:
Bug-Reference-URL:
Bug-Description:
This patch changes the encoding bash uses for exported functions to avoid
clashes with shell variables and to avoid depending only on an environment
variable's contents to determine whether or not to interpret it as a shell
function.
Patch (apply with `patch -p0'):
--- a/variables.c
+++ b/variables.c
@@ -79,6 +79,11 @@
#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')
+#define BASHFUNC_PREFIX "BASH_FUNC_"
+#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */
+#define BASHFUNC_SUFFIX "%%"
+#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */
+
extern char **environ;
/* Variables used here and defined in other files. */
@@ -268,7 +273,7 @@ static void push_temp_var __P((PTR_T));
static void propagate_temp_var __P((PTR_T));
static void dispose_temporary_env __P((sh_free_func_t *));
-static inline char *mk_env_string __P((const char *, const char *));
+static inline char *mk_env_string __P((const char *, const char *, int));
static char **make_env_array_from_var_list __P((SHELL_VAR **));
static char **make_var_export_array __P((VAR_CONTEXT *));
static char **make_func_export_array __P((void));
@@ -338,27 +343,41 @@ initialize_shell_variables (env, privmod
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
- if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
+ if (privmode == 0 && read_but_dont_execute == 0 &&
+ STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
+ STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
+ STREQN ("() {", string, 4))
{
+ size_t namelen;
+ char *tname; /* desired imported function name */
+
+ namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN;
+
+ tname = name + BASHFUNC_PREFLEN; /* start of func name */
+ tname[namelen] = '\0'; /* now tname == func name */
+
string_length = strlen (string);
- temp_string = (char *)xmalloc (3 + string_length + char_index);
+ temp_string = (char *)xmalloc (namelen + string_length + 2);
- strcpy (temp_string, name);
- temp_string[char_index] = ' ';
- strcpy (temp_string + char_index + 1, string);
+ memcpy (temp_string, tname, namelen);
+ temp_string[namelen] = ' ';
+ memcpy (temp_string + namelen + 1, string, string_length + 1);
/* Don't import function names that are invalid identifiers from the
environment. */
- if (legal_identifier (name))
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
+ if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname)))
+ parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
- if (temp_var = find_function (name))
+ if (temp_var = find_function (tname))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
}
else
- report_error (_("error importing function definition for `%s'"), name);
+ report_error (_("error importing function definition for `%s'"), tname);
+
+ /* Restore original suffix */
+ tname[namelen] = BASHFUNC_SUFFIX[0];
}
#if defined (ARRAY_VARS)
# if 0
@@ -2537,7 +2556,7 @@ assign_in_env (word, flags)
var->context = variable_context; /* XXX */
INVALIDATE_EXPORTSTR (var);
- var->exportstr = mk_env_string (name, value);
+ var->exportstr = mk_env_string (name, value, 0);
array_needs_making = 1;
@@ -3389,21 +3408,42 @@ merge_temporary_env ()
/* **************************************************************** */
static inline char *
-mk_env_string (name, value)
+mk_env_string (name, value, isfunc)
const char *name, *value;
+ int isfunc;
{
- int name_len, value_len;
- char *p;
+ size_t name_len, value_len;
+ char *p, *q;
name_len = strlen (name);
value_len = STRLEN (value);
- p = (char *)xmalloc (2 + name_len + value_len);
- strcpy (p, name);
- p[name_len] = '=';
+
+ /* If we are exporting a shell function, construct the encoded function
+ name. */
+ if (isfunc && value)
+ {
+ p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2);
+ q = p;
+ memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN);
+ q += BASHFUNC_PREFLEN;
+ memcpy (q, name, name_len);
+ q += name_len;
+ memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN);
+ q += BASHFUNC_SUFFLEN;
+ }
+ else
+ {
+ p = (char *)xmalloc (2 + name_len + value_len);
+ memcpy (p, name, name_len);
+ q = p + name_len;
+ }
+
+ q[0] = '=';
if (value && *value)
- strcpy (p + name_len + 1, value);
+ memcpy (q + 1, value, value_len + 1);
else
- p[name_len + 1] = '\0';
+ q[1] = '\0';
+
return (p);
}
@@ -3489,7 +3529,7 @@ make_env_array_from_var_list (vars)
/* Gee, I'd like to get away with not using savestring() if we're
using the cached exportstr... */
list[list_index] = USE_EXPORTSTR ? savestring (value)
- : mk_env_string (var->name, value);
+ : mk_env_string (var->name, value, function_p (var));
if (USE_EXPORTSTR == 0)
SAVE_EXPORTSTR (var, list[list_index]);
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 49
+#define PATCHLEVEL 50
#endif /* _PATCHLEVEL_H_ */

View File

@ -0,0 +1,131 @@
BASH PATCH REPORT
=================
Bash-Release: 4.2
Patch-ID: bash42-051
Bug-Reported-by: Florian Weimer <fweimer@redhat.com>
Bug-Reference-ID:
Bug-Reference-URL:
Bug-Description:
There are two local buffer overflows in parse.y that can cause the shell
to dump core when given many here-documents attached to a single command
or many nested loops.
Patch (apply with `patch -p0'):
--- a/parse.y
+++ b/parse.y
@@ -167,6 +167,9 @@ static char *read_a_line __P((int));
static int reserved_word_acceptable __P((int));
static int yylex __P((void));
+
+static void push_heredoc __P((REDIRECT *));
+static char *mk_alexpansion __P((char *));
static int alias_expand_token __P((char *));
static int time_command_acceptable __P((void));
static int special_case_tokens __P((char *));
@@ -264,7 +267,9 @@ int parser_state;
/* Variables to manage the task of reading here documents, because we need to
defer the reading until after a complete command has been collected. */
-static REDIRECT *redir_stack[10];
+#define HEREDOC_MAX 16
+
+static REDIRECT *redir_stack[HEREDOC_MAX];
int need_here_doc;
/* Where shell input comes from. History expansion is performed on each
@@ -306,7 +311,7 @@ static int global_extglob;
or `for WORD' begins. This is a nested command maximum, since the array
index is decremented after a case, select, or for command is parsed. */
#define MAX_CASE_NEST 128
-static int word_lineno[MAX_CASE_NEST];
+static int word_lineno[MAX_CASE_NEST+1];
static int word_top = -1;
/* If non-zero, it is the token that we want read_token to return
@@ -519,42 +524,42 @@ redirection: '>' WORD
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| NUMBER LESS_LESS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| REDIR_WORD LESS_LESS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| LESS_LESS_MINUS WORD
{
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| NUMBER LESS_LESS_MINUS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| REDIR_WORD LESS_LESS_MINUS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
- redir_stack[need_here_doc++] = $$;
+ push_heredoc ($$);
}
| LESS_LESS_LESS WORD
{
@@ -2533,6 +2538,21 @@ yylex ()
which allow ESAC to be the next one read. */
static int esacs_needed_count;
+static void
+push_heredoc (r)
+ REDIRECT *r;
+{
+ if (need_here_doc >= HEREDOC_MAX)
+ {
+ last_command_exit_value = EX_BADUSAGE;
+ need_here_doc = 0;
+ report_syntax_error (_("maximum here-document count exceeded"));
+ reset_parser ();
+ exit_shell (last_command_exit_value);
+ }
+ redir_stack[need_here_doc++] = r;
+}
+
void
gather_here_documents ()
{
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 50
+#define PATCHLEVEL 51
#endif /* _PATCHLEVEL_H_ */

View File

@ -0,0 +1,50 @@
BASH PATCH REPORT
=================
Bash-Release: 4.2
Patch-ID: bash42-052
Bug-Reported-by: Michal Zalewski <lcamtuf@coredump.cx>
Bug-Reference-ID:
Bug-Reference-URL:
Bug-Description:
When bash is parsing a function definition that contains a here-document
delimited by end-of-file (or end-of-string), it leaves the closing delimiter
uninitialized. This can result in an invalid memory access when the parsed
function is later copied.
Patch (apply with `patch -p0'):
--- a/make_cmd.c
+++ b/make_cmd.c
@@ -689,6 +689,7 @@ make_redirection (source, instruction, d
/* First do the common cases. */
temp->redirector = source;
temp->redirectee = dest_and_filename;
+ temp->here_doc_eof = 0;
temp->instruction = instruction;
temp->flags = 0;
temp->rflags = flags;
--- a/copy_cmd.c
+++ b/copy_cmd.c
@@ -126,7 +126,7 @@ copy_redirect (redirect)
{
case r_reading_until:
case r_deblank_reading_until:
- new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
+ new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0;
/*FALLTHROUGH*/
case r_reading_string:
case r_appending_to:
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 51
+#define PATCHLEVEL 52
#endif /* _PATCHLEVEL_H_ */

View File

@ -0,0 +1,114 @@
BASH PATCH REPORT
=================
Bash-Release: 4.2
Patch-ID: bash42-053
Bug-Reported-by: Michal Zalewski <lcamtuf@coredump.cx>
Bug-Reference-ID:
Bug-Reference-URL:
Bug-Description:
A combination of nested command substitutions and function importing from
the environment can cause bash to execute code appearing in the environment
variable value following the function definition.
Patch (apply with `patch -p0'):
--- a/builtins/evalstring.c
+++ b/builtins/evalstring.c
@@ -261,12 +261,25 @@ parse_and_execute (string, from_file, fl
{
struct fd_bitmap *bitmap;
- if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+ if (flags & SEVAL_FUNCDEF)
{
- internal_warning ("%s: ignoring function definition attempt", from_file);
- should_jump_to_top_level = 0;
- last_result = last_command_exit_value = EX_BADUSAGE;
- break;
+ char *x;
+
+ /* If the command parses to something other than a straight
+ function definition, or if we have not consumed the entire
+ string, or if the parser has transformed the function
+ name (as parsing will if it begins or ends with shell
+ whitespace, for example), reject the attempt */
+ if (command->type != cm_function_def ||
+ ((x = parser_remaining_input ()) && *x) ||
+ (STREQ (from_file, command->value.Function_def->name->word) == 0))
+ {
+ internal_warning (_("%s: ignoring function definition attempt"), from_file);
+ should_jump_to_top_level = 0;
+ last_result = last_command_exit_value = EX_BADUSAGE;
+ reset_parser ();
+ break;
+ }
}
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
@@ -331,7 +344,10 @@ parse_and_execute (string, from_file, fl
discard_unwind_frame ("pe_dispose");
if (flags & SEVAL_ONECMD)
- break;
+ {
+ reset_parser ();
+ break;
+ }
}
}
else
--- a/parse.y
+++ b/parse.y
@@ -2435,6 +2435,16 @@ shell_ungetc (c)
eol_ungetc_lookahead = c;
}
+char *
+parser_remaining_input ()
+{
+ if (shell_input_line == 0)
+ return 0;
+ if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len)
+ return '\0'; /* XXX */
+ return (shell_input_line + shell_input_line_index);
+}
+
#ifdef INCLUDE_UNUSED
/* Back the input pointer up by one, effectively `ungetting' a character. */
static void
@@ -3890,8 +3900,8 @@ xparse_dolparen (base, string, indp, fla
reset_parser ();
/* reset_parser clears shell_input_line and associated variables */
restore_input_line_state (&ls);
- if (interactive)
- token_to_read = 0;
+
+ token_to_read = 0;
/* Need to find how many characters parse_and_execute consumed, update
*indp, if flags != 0, copy the portion of the string parsed into RET
--- a/shell.h
+++ b/shell.h
@@ -177,6 +177,8 @@ typedef struct _sh_input_line_state_t {
} sh_input_line_state_t;
/* Let's try declaring these here. */
+extern char *parser_remaining_input __P((void));
+
extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
extern void restore_parser_state __P((sh_parser_state_t *));
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 52
+#define PATCHLEVEL 53
#endif /* _PATCHLEVEL_H_ */

View File

@ -1,83 +0,0 @@
--- a/parse.y
+++ b/parse.y
@@ -264,9 +264,21 @@ int parser_state;
/* Variables to manage the task of reading here documents, because we need to
defer the reading until after a complete command has been collected. */
-static REDIRECT *redir_stack[10];
+static REDIRECT **redir_stack;
int need_here_doc;
+/* Pushes REDIR onto redir_stack, resizing it as needed. */
+static void
+push_redir_stack (REDIRECT *redir)
+{
+ /* Guard against oveflow. */
+ if (need_here_doc + 1 > INT_MAX / sizeof (*redir_stack))
+ abort ();
+ redir_stack = xrealloc (redir_stack,
+ (need_here_doc + 1) * sizeof (*redir_stack));
+ redir_stack[need_here_doc++] = redir;
+}
+
/* Where shell input comes from. History expansion is performed on each
line when the shell is interactive. */
static char *shell_input_line = (char *)NULL;
@@ -519,42 +531,42 @@ redirection: '>' WORD
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| NUMBER LESS_LESS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| REDIR_WORD LESS_LESS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| LESS_LESS_MINUS WORD
{
source.dest = 0;
redir.filename = $2;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| NUMBER LESS_LESS_MINUS WORD
{
source.dest = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, 0);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| REDIR_WORD LESS_LESS_MINUS WORD
{
source.filename = $1;
redir.filename = $3;
$$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
- redir_stack[need_here_doc++] = $$;
+ push_redir_stack ($$);
}
| LESS_LESS_LESS WORD
{
@@ -4759,7 +4771,7 @@ got_token:
case CASE:
case SELECT:
case FOR:
- if (word_top < MAX_CASE_NEST)
+ if (word_top + 1 < MAX_CASE_NEST)
word_top++;
word_lineno[word_top] = line_number;
break;

View File

@ -1,146 +0,0 @@
--- a/variables.c
+++ b/variables.c
@@ -268,7 +268,7 @@ static void push_temp_var __P((PTR_T));
static void propagate_temp_var __P((PTR_T));
static void dispose_temporary_env __P((sh_free_func_t *));
-static inline char *mk_env_string __P((const char *, const char *));
+static inline char *mk_env_string __P((const char *, const char *, int));
static char **make_env_array_from_var_list __P((SHELL_VAR **));
static char **make_var_export_array __P((VAR_CONTEXT *));
static char **make_func_export_array __P((void));
@@ -301,6 +301,14 @@ create_variable_tables ()
#endif
}
+/* Prefix and suffix for environment variable names which contain
+ shell functions. */
+#define FUNCDEF_PREFIX "BASH_FUNC_"
+#define FUNCDEF_PREFIX_LEN (strlen (FUNCDEF_PREFIX))
+#define FUNCDEF_SUFFIX "()"
+#define FUNCDEF_SUFFIX_LEN (strlen (FUNCDEF_SUFFIX))
+
+
/* Initialize the shell variables from the current environment.
If PRIVMODE is nonzero, don't import functions from ENV or
parse $SHELLOPTS. */
@@ -338,27 +346,39 @@ initialize_shell_variables (env, privmod
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
- if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
- {
- string_length = strlen (string);
- temp_string = (char *)xmalloc (3 + string_length + char_index);
+ if (privmode == 0 && read_but_dont_execute == 0
+ && STREQN (FUNCDEF_PREFIX, name, FUNCDEF_PREFIX_LEN)
+ && STREQ (name + char_index - FUNCDEF_SUFFIX_LEN, FUNCDEF_SUFFIX)
+ && STREQN ("() {", string, 4))
+ {
+ size_t name_length
+ = char_index - (FUNCDEF_PREFIX_LEN + FUNCDEF_SUFFIX_LEN);
+ char *temp_name = name + FUNCDEF_PREFIX_LEN;
+ /* Temporarily remove the suffix. */
+ temp_name[name_length] = '\0';
- strcpy (temp_string, name);
- temp_string[char_index] = ' ';
- strcpy (temp_string + char_index + 1, string);
+ string_length = strlen (string);
+ temp_string = (char *)xmalloc (name_length + 1 + string_length + 1);
+ memcpy (temp_string, temp_name, name_length);
+ temp_string[name_length] = ' ';
+ memcpy (temp_string + name_length + 1, string, string_length + 1);
/* Don't import function names that are invalid identifiers from the
environment. */
- if (legal_identifier (name))
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
+ if (legal_identifier (temp_name))
+ parse_and_execute (temp_string, temp_name,
+ SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
- if (temp_var = find_function (name))
+ if (temp_var = find_function (temp_name))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
}
else
report_error (_("error importing function definition for `%s'"), name);
+
+ /* Restore the original suffix. */
+ temp_name[name_length] = FUNCDEF_SUFFIX[0];
}
#if defined (ARRAY_VARS)
# if 0
@@ -2537,7 +2557,7 @@ assign_in_env (word, flags)
var->context = variable_context; /* XXX */
INVALIDATE_EXPORTSTR (var);
- var->exportstr = mk_env_string (name, value);
+ var->exportstr = mk_env_string (name, value, 0);
array_needs_making = 1;
@@ -3388,22 +3408,43 @@ merge_temporary_env ()
/* */
/* **************************************************************** */
+/* Returns the string NAME=VALUE if !FUNCTIONP or if VALUE == NULL (in
+ which case it is treated as empty). Otherwise, decorate NAME with
+ FUNCDEF_PREFIX and FUNCDEF_SUFFIX, and return a string of the form
+ FUNCDEF_PREFIX NAME FUNCDEF_SUFFIX = VALUE (without spaces). */
static inline char *
-mk_env_string (name, value)
+mk_env_string (name, value, functionp)
const char *name, *value;
+ int functionp;
{
- int name_len, value_len;
- char *p;
+ size_t name_len, value_len;
+ char *p, *q;
name_len = strlen (name);
value_len = STRLEN (value);
- p = (char *)xmalloc (2 + name_len + value_len);
- strcpy (p, name);
- p[name_len] = '=';
+ if (functionp && value != NULL)
+ {
+ p = (char *)xmalloc (FUNCDEF_PREFIX_LEN + name_len + FUNCDEF_SUFFIX_LEN
+ + 1 + value_len + 1);
+ q = p;
+ memcpy (q, FUNCDEF_PREFIX, FUNCDEF_PREFIX_LEN);
+ q += FUNCDEF_PREFIX_LEN;
+ memcpy (q, name, name_len);
+ q += name_len;
+ memcpy (q, FUNCDEF_SUFFIX, FUNCDEF_SUFFIX_LEN);
+ q += FUNCDEF_SUFFIX_LEN;
+ }
+ else
+ {
+ p = (char *)xmalloc (name_len + 1 + value_len + 1);
+ memcpy (p, name, name_len);
+ q = p + name_len;
+ }
+ q[0] = '=';
if (value && *value)
- strcpy (p + name_len + 1, value);
+ memcpy (q + 1, value, value_len + 1);
else
- p[name_len + 1] = '\0';
+ q[1] = '\0';
return (p);
}
@@ -3489,7 +3530,7 @@ make_env_array_from_var_list (vars)
/* Gee, I'd like to get away with not using savestring() if we're
using the cached exportstr... */
list[list_index] = USE_EXPORTSTR ? savestring (value)
- : mk_env_string (var->name, value);
+ : mk_env_string (var->name, value, function_p (var));
if (USE_EXPORTSTR == 0)
SAVE_EXPORTSTR (var, list[list_index]);