1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
BASH PATCH REPORT
=================
Bash-Release: 4.3
Patch-ID: bash43-014
Bug-Reported-by: Greg Wooledge <wooledg@eeg.ccf.org>
Bug-Reference-ID: <20140418202123.GB7660@eeg.ccf.org>
Bug-Reference-URL: http://lists.gnu.org/archive/html/help-bash/2014-04/msg00004.html
Bug-Description:
Under certain circumstances, $@ is expanded incorrectly in contexts where
word splitting is not performed.
Patch (apply with `patch -p0'):
*** ../bash-4.3-patched/subst.c 2014-01-23 16:26:37.000000000 -0500
--- subst.c 2014-04-19 15:41:26.000000000 -0400
***************
*** 3249,3254 ****
--- 3249,3256 ----
return ((char *)NULL);
+ expand_no_split_dollar_star = 1;
w->flags |= W_NOSPLIT2;
l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
+ expand_no_split_dollar_star = 0;
if (l)
{
***************
*** 7848,7851 ****
--- 7850,7857 ----
according to POSIX.2, this expands to a list of the positional
parameters no matter what IFS is set to. */
+ /* XXX - what to do when in a context where word splitting is not
+ performed? Even when IFS is not the default, posix seems to imply
+ that we behave like unquoted $* ? Maybe we should use PF_NOSPLIT2
+ here. */
temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
***************
*** 8817,8820 ****
--- 8823,8827 ----
{
char *ifs_chars;
+ char *tstring;
ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
***************
*** 8831,8834 ****
--- 8838,8865 ----
if (split_on_spaces)
list = list_string (istring, " ", 1); /* XXX quoted == 1? */
+ /* If we have $@ (has_dollar_at != 0) and we are in a context where we
+ don't want to split the result (W_NOSPLIT2), and we are not quoted,
+ we have already separated the arguments with the first character of
+ $IFS. In this case, we want to return a list with a single word
+ with the separator possibly replaced with a space (it's what other
+ shells seem to do).
+ quoted_dollar_at is internal to this function and is set if we are
+ passed an argument that is unquoted (quoted == 0) but we encounter a
+ double-quoted $@ while expanding it. */
+ else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
+ {
+ /* Only split and rejoin if we have to */
+ if (*ifs_chars && *ifs_chars != ' ')
+ {
+ list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
+ tstring = string_list (list);
+ }
+ else
+ tstring = istring;
+ tword = make_bare_word (tstring);
+ if (tstring != istring)
+ free (tstring);
+ goto set_word_flags;
+ }
else if (has_dollar_at && ifs_chars)
list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
***************
*** 8836,8839 ****
--- 8867,8871 ----
{
tword = make_bare_word (istring);
+ set_word_flags:
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
tword->flags |= W_QUOTED;
*** ../bash-4.3/patchlevel.h 2012-12-29 10:47:57.000000000 -0500
--- patchlevel.h 2014-03-20 20:01:28.000000000 -0400
***************
*** 26,30 ****
looks for to find the patch level (for the sccs version string). */
! #define PATCHLEVEL 13
#endif /* _PATCHLEVEL_H_ */
--- 26,30 ----
looks for to find the patch level (for the sccs version string). */
! #define PATCHLEVEL 14
#endif /* _PATCHLEVEL_H_ */
|