Re: 4.4 change in behavior from 4.3: how to catch unset when using ${#length}

2016-11-01 Thread Dan Douglas
On Mon, Oct 24, 2016 at 8:25 AM, Chet Ramey  wrote:
> On 10/21/16 5:41 PM, L. A. Walsh wrote:
>> On 4.3 and earlier, at least on arrays, one could have
>> the illusion of this working w/o complaint -- and returning
>> 0 when the array was 0-len or unset, or the array length,
>> otherwise:
>>
>>
>>  echo ${#array[@]:-0}
>>
>> But I note it only seemed to work in arrays, and in 4.4 gets a
>> syntax error:
>>
>>  echo ${#array[@]:-0}   bash: ${#array[@]:-0}: bad substitution
>
> Because it is a syntax error, and if it were not it would be ambiguous.
> The ${param:-word} word expansion takes a parameter, not another word
> expansion, as the object to be expanded.

On a possibly related note, would you consider adjusting +, :+, -, :-,
as in "${var[@]+word}" to align with the meaning of [[ -v var[@] ]] as
discussed in https://lists.gnu.org/archive/html/bug-bash/2014-11/msg00099.html
? I've always felt the best use of that expansion would be to test for
a defined array (or any set array element other than arr[0]).
${var[@]+word}, ${var[0]+word}, and ${var+word} are currently
redundant to my knowledge. The latter two I can understand, but var[@]
seems inconsistent.

My best interpretation of the current behaviour is that it copies that
of $@, which doesn't really make sense IMO because arrays may be
sparse. All the effects of ${@+word} make sense but don't translate
well directly to bash arrays. OTOH [[ -v var[@] ]] since bash 4.3
makes a lot of sense to me and I think they would translate well to
the corresponding parameter expansions.



Re: [PATCH] Add-rm-rf-as-examples-loadables-rm.c

2016-11-01 Thread Tim Ruehsen
On Monday, October 31, 2016 4:44:21 PM CET Eric Blake wrote:
> On 10/31/2016 04:14 PM, Chet Ramey wrote:
> >> > Nice, thanks for the modifications.
> > 
> > Here's the modified version.
> > 
> > Chet
> > -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars
> > longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRU c...@case.edu
> > http://cnswww.cns.cwru.edu/~chet/
> > 
> >   if ((dir = opendir(dirname)))
> >   
> > {
> > 
> >   while ((dp = readdir(dir)))
> 
> Ouch.  This version has O(n^2) complexity when dealing with deep
> hierarchies.  GNU Coreutils intentionally prefers using
> openat()/fdopendir() and so on in order to recurse through the tree with
> O(n) complexity instead of O(n^2).

As Chet stated, the purpose was to speed up ./configure runs. For that I can't 
see very deeply nested directories with million of files in it.

> > {
> > 
> >   if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1]
> >   == '.' && dp->d_name[2] == 0)))>   
> > continue;
> >
> >fnsize = dirlen + 1 + strlen(dp->d_name) + 1;
> >
> >fname = xmalloc (fnsize);
> >snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);
> 
> And here is part of the HUGE speed penalty that you get in large
> directories.  You are mallocing a LOT of memory, and waste a LOT of work
> since the majority of the time (while within a single directory) the
> prefix is unchanged from the previous iteration, while in the deep
> hierarchy; while doing everything directory-relative completely avoids
> the need to construct ever-deeper names.

I agree. My implementation used stack space - which should be fine for real 
file 
names. If in doubt, a simple heap reallocation strategy is just a few lines.
But the purpose argument hits here as well.

> >if (rm_file (fname) && force == 0)
> >
> >  err = 1;
> >
> >free (fname);
> > 
> > }
> 
> Another speed sink - your implementation removes names in readdir()
> order; GNU Coreutils has proven benchmark numbers that unlink()ing files
> that are sorted by inode number is measurably faster than unlink()ing in
> readdir() order for directories with a large number of files.  Yes, it
> is more complex to set up the tracking structures to sort things, but it
> pays off in the long run.

Maybe, but very likely is that completely dependent on the type of file system, 
sounds very hacky.
I wonder why there isn't a system call that recursively removes a directory + 
content, at least for Linux.
Again the purpose argument hits.

> >   while ((opt = internal_getopt (list, "rf")) != -1)
> >   
> > {
> > 
> >   switch (opt)
> > 
> > {
> > 
> > case 'r':
> >   recursive = 1;
> >   break;
> 
> Per POSIX, 'rm -R' and 'rm -r' are identical; a couple tweaks to this
> patch will make support for 'rm -R' work out of the box.

Not needed for the purpose, but doesn't hurt.

> > case 'f':
> >   force = 1;
> >   break;
> > 
> > CASE_HELPOPT;
> > 
> > default:
> >   builtin_usage ();
> >   return (EX_USAGE);
> > 
> > }
> 
> You do NOT support the POSIX-mandated 'rm -i'.  I don't necessarily
> blame you (since it is complex), but what you should REALLY do is that
> any time you don't recognize an option, your builtin should silently
> call the real rm utility, rather than failing.  That way, your builtin
> can be a faster drop-in when it recognizes the simple cases, but remains
> POSIX-compliant (assuming the fallback app is POSIX compliant), as well
> as offer ALL extensions that the normal fallback understands, rather
> than being a crippled version that causes failures to code expecting
> POSIX or particular extension behaviors.

[*]
Such a fallback on unknown options is a good thing. I simply didn't know how 
to do that in an acceptable manner (within a loadable bash builtin). This 
should be done for other loadables as well (e.g. 'cat'). It would serve it's 
purpose as 'example' even better.

> 
> > }
> >   
> >   list = loptend;
> >   
> >   if (list == 0)
> >   
> > return (EXECUTION_SUCCESS);
> 
> This does not match the behavior of GNU coreutils.  'rm' without
> arguments prints a usage error and exits with nonzero status.  But note
> that POSIX requires 'rm -f' without arguments to silently exit with
> success.  POSIX only specifies the behavior of 'rm -f' without
> arguments; with 'rm', you can do what you want (therefore you comply
> with POSIX), but it's still nice to match what other implementations do.

[**]
As you say, preferable it should match with GNU coreutils in this point.

> While I think that it is neat that this builtin can be used to speed up
> configure scripts, I don't think it is ready for prime time yet.  It's
> tough to recommend that autoconf be taught to use this sub-standard
> implementation.

It works wit

Re: [PATCH] Add-rm-rf-as-examples-loadables-rm.c

2016-11-01 Thread Chet Ramey
On 11/1/16 11:41 AM, Tim Ruehsen wrote:

>>>   if ((dir = opendir(dirname)))
>>>   
>>> {
>>> 
>>>   while ((dp = readdir(dir)))
>>
>> Ouch.  This version has O(n^2) complexity when dealing with deep
>> hierarchies.  GNU Coreutils intentionally prefers using
>> openat()/fdopendir() and so on in order to recurse through the tree with
>> O(n) complexity instead of O(n^2).
> 
> As Chet stated, the purpose was to speed up ./configure runs. For that I 
> can't 
> see very deeply nested directories with million of files in it.

The bottom line is to identify the problem you're trying to solve, figure
out the requirements and constraints of that problem, and solve it
efficiently.  In this case, the problem is speeding up configure, the
requirements are only those configure imposes, and the constraints are the
expected sets of files and directories to remove.  If the problem you're
solving doesn't include directory trees with millions of files in deeply
nested directories, don't waste time optimizing the case you're not going
to encounter.

> 
>>> {
>>> 
>>>   if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1]
>>>   == '.' && dp->d_name[2] == 0)))>   
>>> continue;
>>>
>>>fnsize = dirlen + 1 + strlen(dp->d_name) + 1;
>>>
>>>fname = xmalloc (fnsize);
>>>snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);
>>
>> And here is part of the HUGE speed penalty that you get in large
>> directories.  You are mallocing a LOT of memory, and waste a LOT of work
>> since the majority of the time (while within a single directory) the
>> prefix is unchanged from the previous iteration, while in the deep
>> hierarchy; while doing everything directory-relative completely avoids
>> the need to construct ever-deeper names.
> 
> I agree. My implementation used stack space - which should be fine for real 
> file 
> names. If in doubt, a simple heap reallocation strategy is just a few lines.
> But the purpose argument hits here as well.

I agree: if you're not going to use this implementation in a situation
where you have large directories with large numbers of files, don't worry
about that case.  Solve that problem if it becomes a problem.

The allocate-dynamic-arrays-on-the-stack trick only works for gcc and
compilers that masquerade as gcc.  If this turns out to be important, we
can wrap the dynamic array allocation in #if __GNUC__ and go from there.
Given the constraints of this problem, it may not be a big deal.

> 
>>>if (rm_file (fname) && force == 0)
>>>
>>>  err = 1;
>>>
>>>free (fname);
>>> 
>>> }
>>
>> Another speed sink - your implementation removes names in readdir()
>> order; GNU Coreutils has proven benchmark numbers that unlink()ing files
>> that are sorted by inode number is measurably faster than unlink()ing in
>> readdir() order for directories with a large number of files.  Yes, it
>> is more complex to set up the tracking structures to sort things, but it
>> pays off in the long run.

The question is whether that long run can reasonably be expected to make a
difference with this issue and whether the effort and complexity is worth
it.  I suspect that it would take more execution time to set up the extra
data structure you need to do this than to simply remove the files in the
order readdir presents them.

>> Per POSIX, 'rm -R' and 'rm -r' are identical; a couple tweaks to this
>> patch will make support for 'rm -R' work out of the box.
> 
> Not needed for the purpose, but doesn't hurt.

Sure, that's easy enough.


>> You do NOT support the POSIX-mandated 'rm -i'.

Since configure scripts never call `rm -i', I don't see this as any kind
of problem.


> [*]
> Such a fallback on unknown options is a good thing. I simply didn't know how 
> to do that in an acceptable manner (within a loadable bash builtin). This 
> should be done for other loadables as well (e.g. 'cat'). It would serve it's 
> purpose as 'example' even better.
> 
>>
>>> }
>>>   
>>>   list = loptend;
>>>   
>>>   if (list == 0)
>>>   
>>> return (EXECUTION_SUCCESS);
>>
>> This does not match the behavior of GNU coreutils.  'rm' without
>> arguments prints a usage error and exits with nonzero status.  But note
>> that POSIX requires 'rm -f' without arguments to silently exit with
>> success.  POSIX only specifies the behavior of 'rm -f' without
>> arguments; with 'rm', you can do what you want (therefore you comply
>> with POSIX), but it's still nice to match what other implementations do.

Again, easy enough to do.

I totally understand the ideological purity argument Eric is making: we
only want the best solution that addresses every possible case optimally.
I'm usually cool with that.  But in this case, it seems like a little more
pragmatism is called for.

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars l

Re: [PATCH] Add-rm-rf-as-examples-loadables-rm.c

2016-11-01 Thread Eric Blake
On 11/01/2016 10:41 AM, Tim Ruehsen wrote:

>>
>> Ouch.  This version has O(n^2) complexity when dealing with deep
>> hierarchies.  GNU Coreutils intentionally prefers using
>> openat()/fdopendir() and so on in order to recurse through the tree with
>> O(n) complexity instead of O(n^2).
> 
> As Chet stated, the purpose was to speed up ./configure runs. For that I 
> can't 
> see very deeply nested directories with million of files in it.

Except that gnulib DOES have a ./configure test that intentionally DOES
create a very deeply nested directory in order to prove whether the OS
has bugs that it needs to work around.  See
http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=m4/getcwd-path-max.m4;h=2531ccff.
 Okay, that's stretching my argument a bit, since that test DOES try
hard to clean up its deep hierarchy in C rather than making the shell do
it after the fact with rm -r.  But my point is you cannot assume that
the rm module would never be called on to delete deep hierarchies.

[Side note - that particular gnulib test runs in a fraction of a second
with O(n) time on sane OS and file systems, but at least the Windows
2000 NTFS driver had a bug, since fixed in newer versions of Windows,
where the test took O(n^2) time because the OS/file system layer was
tracking things by absolute name even though the test itself was taking
great pains to track things relatively and avoid the user-space O(n^2)
penalty of absolute names.  For several years, I had to pre-prime my
config.site on my Cygwin machines to skip to the correct answer of that
test if I didn't want configure to take several minutes]

>> And here is part of the HUGE speed penalty that you get in large
>> directories.  You are mallocing a LOT of memory, and waste a LOT of work
>> since the majority of the time (while within a single directory) the
>> prefix is unchanged from the previous iteration, while in the deep
>> hierarchy; while doing everything directory-relative completely avoids
>> the need to construct ever-deeper names.
> 
> I agree. My implementation used stack space - which should be fine for real 
> file 
> names. If in doubt, a simple heap reallocation strategy is just a few lines.

If you're going to use stack space, you also have to make sure that deep
hierarchies don't overflow a stack page.  But switching to a heap
strategy may cause speed penalties on the common case of not having deep
hierarchies, so the best code has both styles with a switch based on
heuristics.

> But the purpose argument hits here as well.

And my counterargument hits here as well: If you can cleanly fall back
to the REAL rm any time that you find you are no longer dealing with
your purpose-built quick version, then your quick version can take
shortcuts.  That is, code that calls the real rm once it hits 4k in
depth doesn't even have to worry about heap allocation (that's the real
rm's job, at that point) - but you can only make that dichotomy of fast
for the common case but correct for the corner case if you handle the
corner case by calling into the real rm, rather than failing spectacularly.

> Such a fallback on unknown options is a good thing. I simply didn't know how 
> to do that in an acceptable manner (within a loadable bash builtin). This 
> should be done for other loadables as well (e.g. 'cat'). It would serve it's 
> purpose as 'example' even better.

Yes, this I can agree with - having a GOOD example of how to make a
loadable builtin sanely fall back to the real counterpart would be
useful for all of the loadables to follow.

-- 
Eric Blake   eblake redhat com+1-919-301-3266
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature


4.4: crash in redir10 test; use after free?

2016-11-01 Thread Christian Weisgerber
Running the bash 4.4 regression test suite on OpenBSD/amd64, I noticed
a crash in the redir tests.  Specifically, running redir10.sub with
bash 4.4 causes it to die with a bus error most of the time.

Program terminated with signal 10, Bus error.

#0  0x1c9ad0634009 in find_pipeline (pid=97028, alive_only=1,
jobp=0x7f7ea514) at jobs.c:1481
1481  if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) 
|| PALIVE(p)))
(gdb) p last_procsub_child
$1 = (PROCESS *) 0x1c9d2b698ca0
(gdb) p *last_procsub_child
$2 = {next = 0xdfdfdfdfdfdfdfdf, pid = -538976289, status = -538976289,
  running = -538976289,
  command = 0xdfdfdfdfdfdfdfdf }
(gdb) p /x last_procsub_child->pid 
$3 = 0xdfdfdfdf

This looks like a use after free() since OpenBSD's malloc fills
some of the freed memory with 0xdf.

-- 
Christian "naddy" Weisgerber  na...@mips.inka.de