fix issue with break in nofork comsub when expanding for command word list; add error message if the value of a nameref variable expands to an invalid variable name

This commit is contained in:
Chet Ramey
2025-08-14 10:27:52 -04:00
parent ff6cfb1464
commit 3160c0b89c
8 changed files with 98 additions and 60 deletions
+23
View File
@@ -11563,3 +11563,26 @@ subst.c
expand_word_leave_quoted: if call_expand_word_internal returns an
error, return a NULL WORD_LIST *
Fixes bug with PS1 expansion reported by smart.outfit080@8shield.net
config.h.in
- MAJOR_IN_MKDEV: fix typo
8/8
---
execute_cmd.c
- CHECK_BREAK_AND_CONTINUE: macro to encapsulate common code for
testing `breaking' and `continuing' while in loops
- execute_for_command,execute_arith_for_command,execute_select_command,
execute_while_or_until: replace common code with CHECK_BREAK_AND_CONTINUE
- execute_for_command,execute_select_command: add call to
CHECK_BREAK_AND_CONTINUE after binding variable, in case it contains
a nofork comsub that executes break or continue
Report from Oğuz <oguzismailuysal@gmail.com>
8/11
----
builtins/declare.def
- declare_internal: if the value of an assignment statement expands to
an invalid value for a nameref variable, but the original value is
valid, add an error message for the assignment error
Report from Oğuz <oguzismailuysal@gmail.com>
+3
View File
@@ -1032,6 +1032,9 @@ restart_new_var_name:
{
if (valid_nameref_value (value, 1) == 0)
sh_invalidid (value);
/* what else can cause this to fail? */
else if (flags_on & att_integer)
builtin_error ("%s: expands to invalid variable name for name reference", value);
assign_error++;
/* XXX - unset this variable? or leave it as normal var? */
if (created_var)
+1 -1
View File
@@ -294,7 +294,7 @@
#undef HAVE_ALLOCA_H
/* Define if major/minor/makedev is defined in <sys/mkdev.h> */
#undef MAJOR_IN_MAKEDEV
#undef MAJOR_IN_MKDEV
/* Define if major/minor/makedev is defined in <sys/sysmacros.h> */
#undef MAJOR_IN_SYSMACROS
+24 -59
View File
@@ -320,6 +320,21 @@ do { \
} \
} while (0)
/* Common code to check whether `break' or `continue' was executed. */
#define CHECK_BREAK_AND_CONTINUE() \
if (breaking) \
{ \
breaking--; \
break; \
} \
if (continuing) \
{ \
continuing--; \
if (continuing) \
break; \
} \
do { } while (0)
/* A sort of function nesting level counter */
int funcnest = 0;
int funcnest_max = 0;
@@ -3079,6 +3094,8 @@ execute_for_command (FOR_COM *for_command)
else
v = bind_variable (identifier, list->word->word, 0);
CHECK_BREAK_AND_CONTINUE();
if (v == 0 || ASSIGN_DISALLOWED (v, 0))
{
line_number = save_line_number;
@@ -3105,18 +3122,7 @@ execute_for_command (FOR_COM *for_command)
REAP ();
QUIT;
if (breaking)
{
breaking--;
break;
}
if (continuing)
{
continuing--;
if (continuing)
break;
}
CHECK_BREAK_AND_CONTINUE();
}
loop_level--; interrupt_execution--; retain_fifos--;
@@ -3249,17 +3255,7 @@ execute_arith_for_command (ARITH_FOR_COM *arith_for_command)
/* If the step or test expressions execute `break' or `continue' in a
nofork command substitution or by some other means, break the loop
here. */
if (breaking)
{
breaking--;
break;
}
if (continuing)
{
continuing--;
if (continuing)
break;
}
CHECK_BREAK_AND_CONTINUE();
if (expok == 0)
break;
@@ -3274,18 +3270,7 @@ execute_arith_for_command (ARITH_FOR_COM *arith_for_command)
QUIT;
/* Handle any `break' or `continue' commands executed by the body. */
if (breaking)
{
breaking--;
break;
}
if (continuing)
{
continuing--;
if (continuing)
break;
}
CHECK_BREAK_AND_CONTINUE();
/* Evaluate the step expression. */
line_number = arith_lineno;
@@ -3601,23 +3586,14 @@ execute_select_command (SELECT_COM *select_command)
stupidly_hack_special_variables (identifier);
CHECK_BREAK_AND_CONTINUE();
retval = execute_command (select_command->action);
REAP ();
QUIT;
if (breaking)
{
breaking--;
break;
}
if (continuing)
{
continuing--;
if (continuing)
break;
}
CHECK_BREAK_AND_CONTINUE();
#if defined (KSH_COMPATIBLE_SELECT)
show_menu = 0;
@@ -3837,18 +3813,7 @@ execute_while_or_until (WHILE_COM *while_command, int type)
REAP ();
if (breaking)
{
breaking--;
break;
}
if (continuing)
{
continuing--;
if (continuing)
break;
}
CHECK_BREAK_AND_CONTINUE();
}
loop_level--; interrupt_execution--;
+19
View File
@@ -7514,8 +7514,13 @@ array_length_reference (const char *s)
/* If unbound variables should generate an error, report one and return
failure. */
#if 0 /*TAG:bash-5.4 myoga.murase@gmail.com 4/7/2025 */
if ((var == 0 || invisible_p (var)) && unbound_vars_is_error)
#else
if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
#endif
{
unbound_array_error:
set_exit_status (EXECUTION_FAILURE);
#if 1
/* If the array isn't subscripted with `@' or `*', it's an error. */
@@ -7536,6 +7541,11 @@ array_length_reference (const char *s)
/* We support a couple of expansions for variables that are not arrays.
We'll return the length of the value for v[0], and 1 for v[@] or
v[*]. Return 0 for everything else. */
#if 0 /*TAG:bash-5.4 myoga.murase@gmail.com 4/7/2025 */
/* If the variable is set, but not an array or assoc variable, nounset is
enabled, and the subscript is not one of @, *, or 0, it is an error
treated the same as in previous versions. */
#endif
array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
@@ -7546,6 +7556,10 @@ array_length_reference (const char *s)
return (h ? assoc_num_elements (h) : 0);
else if (array_p (var))
return (array ? array_num_elements (array) : 0);
#if 0 /*TAG:bash-5.4 myoga.murase@gmail.com 4/7/2025 */
else if (unbound_vars_is_error && var_isset (var) == 0)
goto unbound_array_error; /* still non-fatal error */
#endif
else
return (var_isset (var) ? 1 : 0);
}
@@ -7585,6 +7599,11 @@ array_length_reference (const char *s)
}
if (array_p (var))
t = array_reference (array, ind);
#if 0 /*TAG:bash-5.4 myoga.murase@gmail.com 4/7/2025 */
/* if nounset is enabled, scalar variables may only be indexed with 0 */
else if (unbound_vars_is_error && (var_isset (var) == 0 || ind != 0))
goto unbound_array_error; /* still fatal error */
#endif
else
t = (ind == 0) ? value_cell (var) : (char *)NULL;
}
+5
View File
@@ -99,6 +99,11 @@ funsub
in here-documents
after all they work here
and work here
after for
uname
after arith for
1) a[${ break;}]
#? after select
a b c == 1 2 3
== 1 2 3
before return
+18
View File
@@ -77,3 +77,21 @@ exec 4<&-
echo after all they ${word-$(echo work here)}
echo and ${word-${ echo work here; }}
unset x
set -- 'a[${ break;}]'
declare -in x
for x do :; done
echo after for
true; for (( ; $? == 0; ${ ! break;} )); do echo uname; done
echo after arith for
declare -i z
select z in 'a[${ break;}]'
do
echo $z
done <<<1
echo after select
+5
View File
@@ -144,6 +144,11 @@ typedef struct _vlist {
#define attmask_scope 0x0f00000
/* Internal attributes used for variable state management. */
#define att_assigning 0x1000000
#define attmask_state 0xf000000
#define exported_p(var) ((((var)->attributes) & (att_exported)))
#define readonly_p(var) ((((var)->attributes) & (att_readonly)))
#define array_p(var) ((((var)->attributes) & (att_array)))