On Mon, 3 Apr 2023, Michael Schmitz wrote: > On 2/04/23 22:46, Finn Thain wrote: > > > This is odd: > > > > https://sources.debian.org/src/dash/0.5.12-2/src/jobs.c/?hl=1165#L1165 > > > > 1176 do { > > 1177 gotsigchld = 0; > > 1178 do > > 1179 err = wait3(status, flags, NULL); > > 1180 while (err < 0 && errno == EINTR); > > 1181 > > 1182 if (err || (err = -!block)) > > 1183 break; > > 1184 > > 1185 sigblockall(&oldmask); > > 1186 > > 1187 while (!gotsigchld && !pending_sig) > > 1188 sigsuspend(&oldmask); > > 1189 > > 1190 sigclearmask(); > > 1191 } while (gotsigchld); > > 1192 > > 1193 return err; > > > > Execution of dash under gdb doesn't seem to agree with the source code > > above. > > > > If wait3() returns the child pid then the break should execute. And it > > does return the pid (4107) but the while loop was not terminated. Hence > > wait3() was called again and the same breakpoint was hit again. Also, the > > I wonder whether line 1182 got miscompiled by gcc. As err == 4107 it's > > 0 and the break clearly ought to have been taken, and the second > condition (which changes err) does not need to be examined. Do the same > ordering constraints apply to '||' as to '&&' ? >
AFAICT, the source code is valid. This article has some information: https://stackoverflow.com/questions/628526/is-short-circuiting-logical-operators-mandated-and-evaluation-order It looks like I messed up. waitproc() appears to have been invoked twice, which is why wait3 was invoked twice... GNU gdb (Debian 13.1-2) 13.1 ... (gdb) set osabi GNU/Linux (gdb) file /bin/dash Reading symbols from /bin/dash... Reading symbols from /usr/lib/debug/.build-id/aa/4160f84f3eeee809c554cb9f3e1ef0686b8dcc.debug... (gdb) b waitproc Breakpoint 1 at 0xc346: file jobs.c, line 1168. (gdb) b jobs.c:1180 Breakpoint 2 at 0xc390: file jobs.c, line 1180. (gdb) run Starting program: /usr/bin/dash [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/m68k-linux-gnu/libthread_db.so.1". # x=$(:) [Detaching after fork from child process 570] Breakpoint 1, waitproc (status=0xeffff86a, block=1) at jobs.c:1168 1168 jobs.c: No such file or directory. (gdb) c Continuing. Breakpoint 2, waitproc (status=0xeffff86a, block=1) at jobs.c:1180 1180 in jobs.c (gdb) info locals oldmask = {__val = {1997799424, 49154, 396623872, 184321, 3223896090, 53249, 3836788738, 1049411610, 867225601, 3094609920, 0, 1048580, 2857693183, 4184129547, 3435708442, 863764480, 184321, 3844141055, 4190425089, 4127248385, 3094659084, 597610497, 4135112705, 3844079616, 131072, 37355520, 184320, 3878473729, 3844132865, 3094663168, 3549089793, 3844132865}} flags = 2 err = 570 oldmask = <optimized out> flags = <optimized out> err = <optimized out> (gdb) c Continuing. Breakpoint 1, waitproc (status=0xeffff86a, block=0) at jobs.c:1168 1168 in jobs.c (gdb) c Continuing. Breakpoint 2, waitproc (status=0xeffff86a, block=0) at jobs.c:1180 1180 in jobs.c (gdb) info locals oldmask = {__val = {1997799424, 49154, 396623872, 184321, 3223896090, 53249, 3836788738, 1049411610, 867225601, 3094609920, 0, 1048580, 2857693183, 4184129547, 3435708442, 863764480, 184321, 3844141055, 4190425089, 4127248385, 3094659084, 597610497, 4135112705, 3844079616, 131072, 37355520, 184320, 3878473729, 3844132865, 3094663168, 3549089793, 3844132865}} flags = 3 err = -1 oldmask = <optimized out> flags = <optimized out> err = <optimized out> (gdb) c Continuing. # > What does the disassembly of this section look like? > > > while loop should have ended after the first iteration because gotsigchild > > should have been set by the signal handler which executed before wait3() > > even returned... > > Setting gotsigchild > 0 would cause the while loop to continue, no? > Right. Sorry for the noise.