Re: wrong variable name in error message about unbound variable?

2023-10-19 Thread Chet Ramey

On 10/17/23 3:32 PM, Grisha Levit wrote:


The reason is that if there was no variable found prior to expanding
the subscript, bash does not check to see if one was created during
that process.


Thanks, I'll consider it. Behavior varies across shells in this area.

Chet

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: bash tries to parse comsub in quoted PE pattern

2023-10-19 Thread Chet Ramey

On 10/18/23 1:08 PM, Emanuele Torre wrote:

On Wed, Oct 18, 2023 at 11:24:11AM -0400, Chet Ramey wrote:

On 10/18/23 10:50 AM, Chet Ramey wrote:


Is it really ok to break that behaviour?


That's why, if you want the first problem repaired, you have to specify
which word expansions are ok to parse and which are not. Should it be
only command and process substitution, which can independently specify
brace expansions? Should it be other parameter expansions, which can
contain quoted strings and command substitutions? Neither? Both?


It looks like the answer is probably "neither."


I have examined the code, and I now understand why "${foo:-"{1..2}"}"
etc were allowed, but were not supposed to.


We can get closer with changes to how the command substitutions are
parsed while performing brace expansion.



While we are at it, when examining this issue now, I have also noticed
that, regardless of whether brace expansion is enabled or not, the bash
parser always reads single quotes in double quoted PEs as if they are
not literal, even though they are literal if the PE is -, =, or +.

[...]

Could/Should this also be fixed so that  "${foo:-'}"  (and +, and =) is
read correctly? Other shells including ksh93, mksh, dash, NetBSD ash,
and busybox can read it correctly.


It behaves as you want in posix mode. Here's the comment explaning it:

  /* The big hammer.  Single quotes aren't special in double quotes.  The
 problem is that Posix used to say the single quotes are semi-special:
 within a double-quoted ${...} construct "an even number of
 unescaped double-quotes or single-quotes, if any, shall occur." */
  /* This was changed in Austin Group Interp 221 */

Bash in default mode uses its historical behavior, which is what POSIX
originally specified.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: wrong variable name in error message about unbound variable?

2023-10-19 Thread alex xmb sw ratchev
On Thu, Oct 19, 2023, 16:58 Chet Ramey  wrote:

> On 10/17/23 3:32 PM, Grisha Levit wrote:
>
> > The reason is that if there was no variable found prior to expanding
> > the subscript, bash does not check to see if one was created during
> > that process.
>
> Thanks, I'll consider it. Behavior varies across shells in this area.
>

to me , its a valid err of non exist value
another normal is to || true with like = or :=
ah i suggest an shopt , cause imo both approaches are valid but different

greets

Chet
>
> --
> ``The lyf so short, the craft so long to lerne.'' - Chaucer
>  ``Ars longa, vita brevis'' - Hippocrates
> Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
>
>
>


[PATCH] printf %ls/%lc/%Q fixes

2023-10-19 Thread Grisha Levit
A few issues with handling of the new %ls, %lc and %Q conversion
specifications:

The %ls and %lc conversion specifications dereference a null pointer
if used without an argument:

$ (printf %ls)
Segmentation fault: 11
$ (printf %lc)
Segmentation fault: 11

The Q conversion specifier's precision handling applies when precision
is provided as part of the format string, but not when it comes form
an argument:

$ printf '%.1Q\n' '**'
\*
$ printf '%.*Q\n' 1 '**'
\*\*

There is code to handle integer overflow for precision values by capping
values to INT_MAX but it's broken for the %Q conversion specifier due to
reading the value into an int rather than an intmax_t prior to overflow
checks being applied:

$ INT_MAX=$(getconf INT_MAX) OVERFLOW=$((INT_MAX*2 + 3))
$ printf "%.${OVERFLOW}s" XY
XY
$ printf "%.${OVERFLOW}Q" XY
X

A precision value of 0 is ignored for the %ls conversion specification:

$ printf '[%.0s][%.0ls]' X Y
[][Y]

A null argument to the %lc conversion specifier does not produce a null
byte. Per discussion in [1], Bash's behavior matches the standard as it
was written, but this is now considered a defect.

$ printf '[%c][%lc]' '' '' | cat -v
[^@][]

[1] https://austingroupbugs.net/view.php?id=1647
---
 builtins/printf.def | 38 ++
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/builtins/printf.def b/builtins/printf.def
index ae6c75c5..6d3fd9a4 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -252,12 +252,13 @@ static size_t conv_bufsize;
 static inline int
 decodeprec (char *ps)
 {
-  int mpr;
+  intmax_t mpr;

   mpr = *ps++ - '0';
   while (DIGIT (*ps))
 mpr = (mpr * 10) + (*ps++ - '0');
-  return mpr;
+  /* Error if precision > INT_MAX here? */
+  return (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
 }

 int
@@ -490,7 +491,10 @@ printf_builtin (WORD_LIST *list)
ws[0] = wc;
ws[1] = L'\0';

-   r = printwidestr (start, ws, 1, fieldwidth, precision);
+   if (wc == L'\0')
+ r = printstr (start, ws, 1, fieldwidth, precision);
+   else
+ r = printwidestr (start, ws, 1, fieldwidth, precision);
if (r < 0)
  PRETURN (EXECUTION_FAILURE);
break;
@@ -514,7 +518,7 @@ printf_builtin (WORD_LIST *list)

wp = getwidestr (&slen);
r = printwidestr (start, wp, slen, fieldwidth, precision);
-   free (wp);
+   FREE (wp);
if (r < 0)
  PRETURN (EXECUTION_FAILURE);
break;
@@ -647,20 +651,19 @@ printf_builtin (WORD_LIST *list)
case 'Q':
  {
char *p, *xp;
-   int r, mpr;
+   int r;
size_t slen;

r = 0;
p = getstr ();
/* Decode precision and apply it to the unquoted string. */
-   if (convch == 'Q' && precstart)
+   if (convch == 'Q' && (have_precision || precstart))
  {
-   mpr = decodeprec (precstart);
-   /* Error if precision > INT_MAX here? */
-   precision = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
+   if (precstart)
+ precision = decodeprec (precstart);
slen = strlen (p);
/* printf precision works in bytes. */
-   if (precision < slen)
+   if (precision >= 0 && precision < slen)
  p[precision] = '\0';
  }
if (p && *p == 0)   /* XXX - getstr never returns null */
@@ -1517,6 +1520,14 @@ getwidestr (size_t *lenp)
   wchar_t *ws;
   const char *mbs;
   size_t slen, mblength;
+
+  if (garglist == 0)
+{
+  if (lenp)
+   *lenp = 0;
+  return NULL;
+}
+
   DECLARE_MBSTATE;

   mbs = garglist->word->word;
@@ -1545,8 +1556,11 @@ getwidechar (void)
 {
   wchar_t wc;
   size_t slen, mblength;
-  DECLARE_MBSTATE;

+  if (garglist == 0)
+return L'\0';
+
+  DECLARE_MBSTATE;
   wc = 0;
   mblength = mbrtowc (&wc, garglist->word->word, locale_mb_cur_max, &state);
   if (MB_INVALIDCH (mblength))
@@ -1571,7 +1585,7 @@ convwidestr (wchar_t *ws, int prec)

   ts = (const wchar_t *)ws;

-  if (prec > 0)
+  if (prec >= 0)
 {
   rsize = prec * MB_CUR_MAX;
   ret = (char *)xmalloc (rsize + 1);
-- 
2.42.0



Re: using a variable from global scope or checking whether it is local to some scope

2023-10-19 Thread ikhxcsz7y xmbott
On Thu, Oct 19, 2023, 23:42 Christoph Anton Mitterer 
wrote:

> Hey Alex.
>
> On Thu, 2023-10-19 at 22:17 +0200, alex xmb sw ratchev wrote:
> > another answer
> > in ur code , force global / local whenever u need it
> >
> > ~ $ ( declare -g a ; a=2 ; declare -p a ; declare a ; declare -p a ;
> > a=3 )
> > declare -- a="2"
> > declare -- a="2"
> > ~ $
> >
> > sadly i didnt find difference there
> > but just declare -g or non -g when u need
>
> I don't understand how this should help?
> Yes it allows me to set the global one, but I cannot expand it?
>

1 i mean when u need a change of local to global back u add this to the
code ..
2 it seems me bug in bash :

~ $ ( declare -g a ; a=2 ; declare -p a ; declare a ; a=3 ; declare -p a ;
declare -g a ; declare -p a ; a=4 ; declare -p a )

declare -- a="2"
declare -- a="3"
declare -- a="3"
declare -- a="4"

the third is from local back global , but it says value of local ( 3 ) and
not original value ( 2 )

a=global
>
> other()
> {
>local a=from_other
>mine
>echo $a
> }
>
> mine()
> {
>echo $a
>( declare -g a ; echo $a; declare -p a )
>
> }
>
> echo $a
> other
>
>
> gives:
> global
> from_other
> from_other
> declare -- a="from_other"
> from_other
>
>
>
> Cheers,
> Chris.
>
>


[PATCH] printf width/precision argument overflow

2023-10-19 Thread Grisha Levit
When reading a printf width/precision argument, the value isn't checked
for overflow if it happens to be the last argument:

$ INT_MAX=$(getconf INT_MAX)
$ printf '[%*s]' "$((INT_MAX+1))"
[]
$ printf '[%*s]' "$((INT_MAX+1))" X
-bash: printf: X: Result too large
[]

..and the following argument is used in the error message if it exists.
---
 builtins/printf.def | 23 +++
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/builtins/printf.def b/builtins/printf.def
index 6d3fd9a4..5030b788 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -1343,13 +1343,27 @@ static int
 getint (void)
 {
   intmax_t ret;
-
-  ret = getintmax ();
+  char *ep;

   if (garglist == 0)
-return ret;
+return (0);
+
+  if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+return asciicode ();

-  if (ret > INT_MAX)
+  errno = 0;
+  ret = strtoimax (garglist->word->word, &ep, 0);
+
+  if (*ep)
+{
+  sh_invalidnum (garglist->word->word);
+  conversion_error = 1;
+}
+  else if (errno == ERANGE)
+{
+  printf_erange (garglist->word->word);
+}
+  else if (ret > INT_MAX)
 {
   printf_erange (garglist->word->word);
   ret = INT_MAX;
@@ -1360,6 +1374,7 @@ getint (void)
   ret = INT_MIN;
 }

+  garglist = garglist->next;
   return ((int)ret);
 }

-- 
2.42.0