zsh-workers
 help / color / mirror / code / Atom feed
* funny subshell effect
@ 2011-03-09 23:18 Mikael Magnusson
  2011-03-10  0:29 ` Phil Pennock
  2011-03-10 14:56 ` Bart Schaefer
  0 siblings, 2 replies; 5+ messages in thread
From: Mikael Magnusson @ 2011-03-09 23:18 UTC (permalink / raw)
  To: zsh workers

This confused me for a few minutes, I was trying to play a random midi file with
pmidi *(oe:REPLY=\$RANDOM:[1])
but it plays the same one each time, but when i tried
echo *(oe:REPLY=\$RANDOM:[1])
it printed a different one each time

% repeat 3; do echo .(e:REPLY=\$RANDOM:); done
17
25549
6369
% repeat 3; do command echo .(e:REPLY=\$RANDOM:); done
5801
5801
5801

Is this something that must be so? (My guess is yes, but it can't hurt to ask).
(I know I can work around it easily by assigning to a var first).

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: funny subshell effect
  2011-03-09 23:18 funny subshell effect Mikael Magnusson
@ 2011-03-10  0:29 ` Phil Pennock
  2011-03-10 14:56 ` Bart Schaefer
  1 sibling, 0 replies; 5+ messages in thread
From: Phil Pennock @ 2011-03-10  0:29 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: zsh workers

On 2011-03-10 at 00:18 +0100, Mikael Magnusson wrote:
> This confused me for a few minutes, I was trying to play a random midi file with
> pmidi *(oe:REPLY=\$RANDOM:[1])
> but it plays the same one each time, but when i tried
> echo *(oe:REPLY=\$RANDOM:[1])
> it printed a different one each time
> 
> % repeat 3; do echo .(e:REPLY=\$RANDOM:); done
> 17
> 25549
> 6369
> % repeat 3; do command echo .(e:REPLY=\$RANDOM:); done
> 5801
> 5801
> 5801
> 
> Is this something that must be so? (My guess is yes, but it can't hurt to ask).
> (I know I can work around it easily by assigning to a var first).

If you assign to RANDOM in the subshell, that's a call to srand() which
will re-seed the RNG.

At present, the retrieval is just:
zlong
randomgetfn(UNUSED(Param pm))
{
    return rand() & 0x7fff;
}

Given the amount of forking going on normally, reseeding on every fork
would be bad, but perhaps something similar to the code I added to Exim
would work, so:

zlong
randomgetfn(UNUSED(Param pm))
{
  static pid_t last_rand_pid = 0;
  pid_t p;

  p = getpid()
  if (p != last_rand_pid)
    {
    last_rand_pid = p;
#ifdef HAVE_SRANDOMDEV_OR_WHATEVER_ZSH_HAS_AS_GUARD
    srandomdev();
#else
    gettimeofday(&tv, NULL);
    srandom(tv.tv_sec | tv.tv_usec | getpid());
#endif
    }
  return rand() & 0x7fff;
}

Except that I actually made Exim prefer arc4random()/arc4random_stir()
if available, and actually uses much stronger randomness from OpenSSL if
linked against that, but that's because people cook up homebrew access
token stuff and I wanted to provide something "not guaranteed
cryptographically strong, but at least not a complete nightmare".

Anyway, does this look like a reasonable approach?

-Phil


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: funny subshell effect
  2011-03-09 23:18 funny subshell effect Mikael Magnusson
  2011-03-10  0:29 ` Phil Pennock
@ 2011-03-10 14:56 ` Bart Schaefer
  2011-03-10 15:11   ` Mikael Magnusson
  1 sibling, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2011-03-10 14:56 UTC (permalink / raw)
  To: zsh workers

On Mar 10, 12:18am, Mikael Magnusson wrote:
} Subject: funny subshell effect
}
} % repeat 3; do command echo .(e:REPLY=\$RANDOM:); done
} 5801
} 5801
} 5801
} 
} Is this something that must be so?

Yep, it's intentional.  Read the manual:

     The values of RANDOM form an intentionally-repeatable pseudo-random
     sequence; subshells that reference RANDOM will result in identical
     pseudo-random values unless the value of RANDOM is referenced or
     seeded in the parent shell in between subshell invocations.

Above that, "The random number generator can be seeded by assigning a
numeric value to RANDOM."

% for i in {1..3}; do command echo .(e:RANDOM=$i\;REPLY=\$RANDOM:); done
17767
6138
20026

If you're not generating more than one number per second, a good way
to see the generator is with $SECONDS.  Or if your system supports a
higher granularity clock, something like

    typeset -F SECONDS
    repeat 3; do
      command echo .(e:'RANDOM=$((SECONDS*1000));REPLY=$RANDOM':);
    done

Consequently, Phil ... your approach may be reasonable, but we don't
want to apply it. :-)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: funny subshell effect
  2011-03-10 14:56 ` Bart Schaefer
@ 2011-03-10 15:11   ` Mikael Magnusson
  2011-03-17  3:44     ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: Mikael Magnusson @ 2011-03-10 15:11 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

On 10 March 2011 15:56, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Mar 10, 12:18am, Mikael Magnusson wrote:
> } Subject: funny subshell effect
> }
> } % repeat 3; do command echo .(e:REPLY=\$RANDOM:); done
> } 5801
> } 5801
> } 5801
> }
> } Is this something that must be so?
>
> Yep, it's intentional.  Read the manual:
>
>     The values of RANDOM form an intentionally-repeatable pseudo-random
>     sequence; subshells that reference RANDOM will result in identical
>     pseudo-random values unless the value of RANDOM is referenced or
>     seeded in the parent shell in between subshell invocations.

Well, I know that part, what confused me was that I wasn't starting
any subshells. But it seems that globbing is performed after forking
to run an external command, and of course zsh doesn't bother to fork
if the command is builtin. Is there some reason I'm not thinking of
why it's like that?

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: funny subshell effect
  2011-03-10 15:11   ` Mikael Magnusson
@ 2011-03-17  3:44     ` Bart Schaefer
  0 siblings, 0 replies; 5+ messages in thread
From: Bart Schaefer @ 2011-03-17  3:44 UTC (permalink / raw)
  To: zsh workers

On Mar 10,  4:11pm, Mikael Magnusson wrote:
} Subject: Re: funny subshell effect
}
} On 10 March 2011 15:56, Bart Schaefer <schaefer@brasslantern.com> wrote:
} > On Mar 10, 12:18am, Mikael Magnusson wrote:
} > } Subject: funny subshell effect
} > }
} > } % repeat 3; do command echo .(e:REPLY=\$RANDOM:); done
} > } 5801
} > } 5801
} > } 5801
} >
} ... what confused me was that I wasn't starting
} any subshells. But it seems that globbing is performed after forking
} to run an external command, and of course zsh doesn't bother to fork
} if the command is builtin. Is there some reason I'm not thinking of
} why it's like that?

It bothered me that I couldn't come up with a reason for this.  The one
that comes to mind is that if a glob goes runaway (you use ***/ with
a path that contains a cyclic symlink, for example) with a builtin you
may not be able to interrupt it; whereas with an external command where
the glob is running post-fork, you are able to interrupt.  Or that may
be a former bug and now it would be OK ... I wasn't willing to try to
lock up my shell to find out.

In fact zsh globs the word in command position separately before the
fork, and then globs the rest of the list afterward.  This leads to
strange bits like this:

% touch noglob
% n*b echo x*
x*
%

It also leads to this:

% repeat 3 do command echo x*  
repeat> done
zsh: no match
zsh: no match
zsh: no match
% repeat 3 do builtin echo x*
done
zsh: no match
% 

With the fork, the globbing error applies only to the forked process,
before the exec has occurred.  I tried wholesale moving the globlist()
up to before any decision about forking is made (sample patch below),
and all the "make check" tests pass; the only obvious difference is
that the two examples shown above become identical -- both run the
loop exactly once.

Compare this to discussion "exec -a and parameter expansion" from the
zsh-workers archive back in January.  That sort of died out without a
resolution.  I suspect that the patch below has some similar obscure
problems.  For example certain files in /proc will point to different
places, or possibly not exist at all, if globbing precedes forking;
that could in turn affect redirection, etc.


--- 8< --- EXAMPLE ONLY - NOT FOR ACTUAL USE --- 8< ---
Index: Src/exec.c
===================================================================
RCS file: /extra/cvsroot/zsh/zsh-4.0/Src/exec.c,v
retrieving revision 1.40
diff -c -r1.40 exec.c
--- exec.c	21 Dec 2010 16:41:16 -0000	1.40
+++ exec.c	17 Mar 2011 03:10:42 -0000
@@ -2735,6 +2744,16 @@
 	}
     }
 
+    if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) {
+	LinkList oargs = args;
+	globlist(args, 0);
+	args = oargs;
+    }
+    if (errflag) {
+	lastval = 1;
+	goto err;
+    }
+
     /* This is nonzero if the command is a current shell procedure? */
     is_cursh = (is_builtin || is_shfunc || nullexec || type >= WC_CURSH);
 
@@ -2844,16 +2863,6 @@
 	is_exec = 1;
     }
 
-    if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) {
-	LinkList oargs = args;
-	globlist(args, 0);
-	args = oargs;
-    }
-    if (errflag) {
-	lastval = 1;
-	goto err;
-    }
-
     /* Make a copy of stderr for xtrace output before redirecting */
     fflush(xtrerr);
     if (isset(XTRACE) && xtrerr == stderr &&


-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-03-17  3:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-09 23:18 funny subshell effect Mikael Magnusson
2011-03-10  0:29 ` Phil Pennock
2011-03-10 14:56 ` Bart Schaefer
2011-03-10 15:11   ` Mikael Magnusson
2011-03-17  3:44     ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).