I am currently recode the Strace command.
I understand the goal of this command and I can catch some syscalls from an exectuable file.
My question is : Why I don't catch the "write" syscall ?
this is my code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <wait.h>
int main(int argc, char* argv[]) {
int status;
pid_t pid;
struct user_regs_struct regs;
int counter = 0;
int in_call =0;
switch(pid = fork()) {
case -1:
perror("fork");
exit(1);
case 0:
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execvp(argv[1], argv + 1);
break;
default:
wait(&status);
while (status == 1407) {
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
if(!in_call) {
printf("SystemCall %lld called with %lld, %lld, %lld\n",regs.orig_rax,
regs.rbx, regs.rcx, regs.rdx);
in_call=1;
counter ++;
}
else
in_call = 0;
ptrace(PTRACE_SYSEMU, pid, NULL, NULL);
wait(&status);
}
}
printf("Total Number of System Calls = %d\n", counter);
return 0;
}
This is the output using my program :
./strace ./my_program
SystemCall 59 called with 0, 0, 0
SystemCall 60 called with 0, 4198437, 5
Total Number of System Calls = 2
59 represents the execve syscall.
60 represents the exit syscall.
This is the output using the real strace :
strace ./my_program
execve("./my_program", ["./bin_asm_write"], 0x7ffd2929ae70 /* 67 vars */) = 0
write(1, "Toto\n", 5Toto
) = 5
exit(0) = ?
+++ exited with 0 +++
As you can see, my program don't catch the write syscall.
I don't understrand why, do you have any idea ?
Thank You for your answer.
Your while loop is set up rather strangely -- you have this in_call flag that you toggle back and forth between 0 and 1, and you only print the system call when it is 0. The net result is that while you catch every system call, you only print every other system call. So when you catch the write call, the flag is 1 and you don't print anything.
Another oddness is that you're using PTRACE_SYSEMU rather than PTRACE_SYSCALL. SYSEMU is intended for emulating system calls, so the system call won't actually run at all (it will be skipped); normally your ptracing program would do whatever the systme call is supposed to do itself and then call PTRACE_SETREGS to set the tracee's registers with the appropriate return values before calling PTRACE_SYSEMU again to run to the next system call.
Your in_call flagging would make more sense if you were actually using PTRACE_SYSCALL, as that will stop twice for each syscall -- once on entry to the syscall and a second time when the call returns. However, it will also stop for signals, so you need to be decoding the status to see if a signal has occurred or not.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv) {
for(int i = 0; i < 10; i++) {
pid_t pid = fork();
if(pid == 0) {
while(1) {
pid_t pid2 = fork();
wait(NULL);
}
}
}
wait(NULL);
return(0);
}
Basically the program runs several hello world processes and closes with ctrl+C. How would I do the wait error? Like perror(wait). I think I have to use int status instead of NULL but unsure how to go about it when theres orphan processes involved.
The given code is
$ gcc -Wall above.c
$ ./a.out
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
^C (until ctrl C is hit)
$
The function perror is only useful when you know that a function failed and
errno is set, so you want to print an error message. You usually write
perror("something failed") right after the function that could fail and
sets errno (the documentation of the function will tell you whether the
function set errno on failure).
man perror
SYNOPSIS
#include <stdio.h>
void perror(const char *s);
#include <errno.h>
DESCRIPTION
The perror() function produces a message on standard error describing the last error encountered during a call to a system or library
function....
This has nothing to do with wait and it's parameter, it's only useful if
wait fails and you want to print an error message about wait failing.
man wait
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
DESCRIPTION
All of these system calls are used to wait for state changes in a child of the calling process...
...
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&wstatus) is
equivalent to:
waitpid(-1, &wstatus, 0);
...
RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
...
Each of these calls sets errno to an appropriate value in the case of an error.
If you just want to wait for a child to exit, you can do just wait(NULL).
However if you want to know the status of the child that exited, then you have
to pass a pointer to int.
int wstatus;
pid_t wp = wait(&wstatus);
if(wp == -1)
{
// here I use perror because if wait returns -1 then there
// was an error and errno is set
perror("could not wait for child\n");
exit(1);
}
if(WIFEXITED(wstatus))
printf("Child with pid %d exited normally with status %d\n", wp, WEXITSTATUS(wstatus));
else
printf("Child with pid %d exited abnormally\n", wp);
I personally prefer waitpid over wait, it gives you more control over the
child you are waiting.
See man wait
This is fairly simple application which creates a lightweight process (thread) with clone() call.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#define STACK_SIZE 1024*1024
int func(void* param) {
printf("I am func, pid %d\n", getpid());
return 0;
}
int main(int argc, char const *argv[]) {
printf("I am main, pid %d\n", getpid());
void* ptr = malloc(STACK_SIZE);
printf("I am calling clone\n");
int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
// works fine with sleep() call
// sleep(1);
if (res == -1) {
printf("clone error: %d", errno);
} else {
printf("I created child with pid: %d\n", res);
}
printf("Main done, pid %d\n", getpid());
return 0;
}
Here are results:
Run 1:
➜ LFD401 ./clone
I am main, pid 10974
I am calling clone
I created child with pid: 10975
Main done, pid 10974
I am func, pid 10975
Run 2:
➜ LFD401 ./clone
I am main, pid 10995
I am calling clone
I created child with pid: 10996
I created child with pid: 10996
I am func, pid 10996
Main done, pid 10995
Run 3:
➜ LFD401 ./clone
I am main, pid 11037
I am calling clone
I created child with pid: 11038
I created child with pid: 11038
I am func, pid 11038
I created child with pid: 11038
I am func, pid 11038
Main done, pid 11037
Run 4:
➜ LFD401 ./clone
I am main, pid 11062
I am calling clone
I created child with pid: 11063
Main done, pid 11062
Main done, pid 11062
I am func, pid 11063
What is going on here? Why "I created child" message is sometimes printed several times?
Also I noticed that adding a delay after clone call "fixes" the problem.
You have a race condition (i.e.) you don't have the implied thread safety of stdio.
The problem is even more severe. You can get duplicate "func" messages.
The problem is that using clone does not have the same guarantees as pthread_create. (i.e.) You do not get the thread safe variants of printf.
I don't know for sure, but, IMO the verbiage about stdio streams and thread safety, in practice, only applies when using pthreads.
So, you'll have to handle your own interthread locking.
Here is a version of your program recoded to use pthread_create. It seems to work without incident:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#define STACK_SIZE 1024*1024
void *func(void* param) {
printf("I am func, pid %d\n", getpid());
return (void *) 0;
}
int main(int argc, char const *argv[]) {
printf("I am main, pid %d\n", getpid());
void* ptr = malloc(STACK_SIZE);
printf("I am calling clone\n");
pthread_t tid;
pthread_create(&tid,NULL,func,NULL);
//int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
int res = 0;
// works fine with sleep() call
// sleep(1);
if (res == -1) {
printf("clone error: %d", errno);
} else {
printf("I created child with pid: %d\n", res);
}
pthread_join(tid,NULL);
printf("Main done, pid %d\n", getpid());
return 0;
}
Here is a test script I've been using to check for errors [it's a little rough, but should be okay]. Run against your version and it will abort quickly. The pthread_create version seems to pass just fine
#!/usr/bin/perl
# clonetest -- clone test
#
# arguments:
# "-p0" -- suppress check for duplicate parent messages
# "-c0" -- suppress check for duplicate child messages
# 1 -- base name for program to test (e.g. for xyz.c, use xyz)
# 2 -- [optional] number of test iterations (DEFAULT: 100000)
master(#ARGV);
exit(0);
# master -- master control
sub master
{
my(#argv) = #_;
my($arg,$sym);
while (1) {
$arg = $argv[0];
last unless (defined($arg));
last unless ($arg =~ s/^-(.)//);
$sym = $1;
shift(#argv);
$arg = 1
if ($arg eq "");
$arg += 0;
${"opt_$sym"} = $arg;
}
$opt_p //= 1;
$opt_c //= 1;
printf("clonetest: p=%d c=%d\n",$opt_p,$opt_c);
$xfile = shift(#argv);
$xfile //= "clone1";
printf("clonetest: xfile='%s'\n",$xfile);
$itermax = shift(#argv);
$itermax //= 100000;
$itermax += 0;
printf("clonetest: itermax=%d\n",$itermax);
system("cc -o $xfile -O2 $xfile.c -lpthread");
$code = $? >> 8;
die("master: compile error\n")
if ($code);
$logf = "/tmp/log";
for ($iter = 1; $iter <= $itermax; ++$iter) {
printf("iter: %d\n",$iter)
if ($opt_v);
dotest($iter);
}
}
# dotest -- perform single test
sub dotest
{
my($iter) = #_;
my($parcnt,$cldcnt);
my($xfsrc,$bf);
system("./$xfile > $logf");
open($xfsrc,"<$logf") or
die("dotest: unable to open '$logf' -- $!\n");
while ($bf = <$xfsrc>) {
chomp($bf);
if ($opt_p) {
while ($bf =~ /created/g) {
++$parcnt;
}
}
if ($opt_c) {
while ($bf =~ /func/g) {
++$cldcnt;
}
}
}
close($xfsrc);
if (($parcnt > 1) or ($cldcnt > 1)) {
printf("dotest: fail on %d -- parcnt=%d cldcnt=%d\n",
$iter,$parcnt,$cldcnt);
system("cat $logf");
exit(1);
}
}
UPDATE:
Were you able to recreate OPs problem with clone?
Absolutely. Before I created the pthreads version, in addition to testing OP's original version, I also created versions that:
(1) added setlinebuf to the start of main
(2) added fflush just before the clone and __fpurge as the first statement of func
(3) added an fflush in func before the return 0
Version (2) eliminated the duplicate parent messages, but the duplicate child messages remained
If you'd like to see this for yourself, download OP's version from the question, my version, and the test script. Then, run the test script on OP's version.
I posted enough information and files so that anyone can recreate the problem.
Note that due to differences between my system and OP's, I couldn't at first reproduce the problem on just 3-4 tries. So, that's why I created the script.
The script does 100,000 test runs and usually the problem will manifest itself within 5000-15000.
I can't recreate OP's issue, but I don't think the printf's are actually a problem.
glibc docs:
The POSIX standard requires that by default the stream operations are
atomic. I.e., issuing two stream operations for the same stream in two
threads at the same time will cause the operations to be executed as
if they were issued sequentially. The buffer operations performed
while reading or writing are protected from other uses of the same
stream. To do this each stream has an internal lock object which has
to be (implicitly) acquired before any work can be done.
Edit:
Even though the above is true for threads, as rici points out, there is a comment on sourceware:
Basically, there's nothing you can safely do with CLONE_VM unless the
child restricts itself to pure computation and direct syscalls (via
sys/syscall.h). If you use any of the standard library, you risk the
parent and child clobbering each other's internal states. You also
have issues like the fact that glibc caches the pid/tid in userspace,
and the fact that glibc expects to always have a valid thread pointer
which your call to clone is unable to initialize correctly because it
does not know (and should not know) the internal implementation of
threads.
Apparently, glibc isn't designed to work with clone if CLONE_VM is set but CLONE_THREAD|CLONE_SIGHAND are not.
Your processes both use the same stdout (that is, the C standard library FILE struct), which includes an accidentally shared buffer. That's undoubtedly causing problems.
Ass everyone suggests: it really seems to be a problem with, how shall I put it in case of clone(), process-safety? With a rough sketch of a locking version of printf (using write(2)) the output is as expected.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#define STACK_SIZE 1024*1024
// VERY rough attempt at a thread-safe printf
#include <stdarg.h>
#define SYNC_REALLOC_GROW 64
int sync_printf(const char *format, ...)
{
int n, all = 0;
int size = 256;
char *p, *np;
va_list args;
if ((p = malloc(size)) == NULL)
return -1;
for (;;) {
va_start(args, format);
n = vsnprintf(p, size, format, args);
va_end(args);
if (n < 0)
return -1;
all += n;
if (n < size)
break;
size = n + SYNC_REALLOC_GROW;
if ((np = realloc(p, size)) == NULL) {
free(p);
return -1;
} else {
p = np;
}
}
// write(2) shoudl be threadsafe, so just in case
flockfile(stdout);
n = (int) write(fileno(stdout), p, all);
fflush(stdout);
funlockfile(stdout);
va_end(args);
free(p);
return n;
}
int func(void *param)
{
sync_printf("I am func, pid %d\n", getpid());
return 0;
}
int main()
{
sync_printf("I am main, pid %d\n", getpid());
void *ptr = malloc(STACK_SIZE);
sync_printf("I am calling clone\n");
int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
// works fine with sleep() call
// sleep(1);
if (res == -1) {
sync_printf("clone error: %d", errno);
} else {
sync_printf("I created child with pid: %d\n", res);
}
sync_printf("Main done, pid %d\n\n", getpid());
return 0;
}
For the third time: it's only a sketch, no time for a robust version, but that shouldn't hinder you to write one.
As evaitl points out printf is documented to be thread-safe by glibc's documentation. BUT, this typically assumes that you are using the designated glibc function to create threads (that is, pthread_create()). If you do not, then you are on your own.
The lock taken by printf() is recursive (see flockfile). This means that if the lock is already taken, the implementation checks the owner of the lock against the locker. If the locker is the same as the owner, the locking attempt succeeds.
To distinguish between different threads, you need to setup properly TLS, which you do not do, but pthread_create() does. What I'm guessing happens is that in your case the TLS variable that identifies the thread is the same for both threads, so you end up taking the lock.
TL;DR: please use pthread_create()
I'm using fork to create a process on a Mac platform, and wait for the child process to finish in the parent process. But the waitpid return -1 and errno is 4 (EINTR).
The example code, which can reproduce this problem, is as follows:
#include <iostream>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main(int argc, const char *argv[])
{
pid_t pid = ::fork();
if (pid == 0)
{
return 0;
}
int s = 0;
if (::waitpid(pid, &s, 0) == -1)
{
printf("The errno is :%d\n", errno); // <<<The errno is 4(EINTR) in my machine.
assert(false); // <<<<This will be hit if run in debugger.
}
return 0;
}
When I run this code in GDB or LLDB the assert will always be hit. If not run in debugger it will not return -1.
I think there is something I don't understand about how debugger or fork/waitpid works. So can anyone explain why this happen?
The debugger is sending a signal to the process. As WhozCraig said, these should be handled by detecting EINTR and calling waitpid again in a loop. Be aware that when running the child process in the debugger, the debugger likely changes the parent process to the debugger's PID, so waitpid on the child PID will fail thinking the child process has exited, even though it has not. When the debugger exits, it restores the PPID of the child to the original parent's PID.
I want from parent program (called daemon) to start 5 child processes of test program with args(all 5 in parallel, not to wait to finish).
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char* argv[]){
//missing irrelevant part where argum is set
int status,i;
char cmd[512];
pid_t process_id = 0;
for (i=0; i<=5;i++)
{
process_id = fork();
if (process_id < 0)
{
printf("fork failed - %d!\n",i);
continue;
}
else if(process_id > 0) {
printf("process_id of child process %d \n", process_id);
}
else
{
sprintf(cmd,"./test %s",argum);
status = system(cmd);
exit(0);
}
}
return 0;
}
it starts them but when I run ps -aux to see the processes, besides the good ones (like: ./test [args]) there are some duplicates like: sh -c ./test [args]
How can I get rid of those starting with "sh -c" ?
Instead of calling system() from the child, use a member of the exec*() family of functions.
Calling execXYZ() from the fork()ed off child process replaces the child process by the new process created from what had been passed to the execXYZ() call.
Please note that if execXYZ() succeeds it does not return.
Example for executing /bin/ls -alrt *.c:
The execl*() members of the family expect each white-space separate command line option as a single parameter.
execl("/bin/ls", "ls", "-alrt", "*.c", (char*) 0);
execlp("ls", "ls", "-alrt", "*.c", (char*) 0);
The execv*() members of the family expect each white-space separate command line option in the way parameters are passed to main():
char * const argv[] = {
"ls",
"-alrt",
"*.c",
NULL,
}
execv("/bin/ls", argv);
execvp("ls", argv);
The exec*p() family members make use of the environment's variable PATH to search for the binary to be executed. So for this example (as for the system command ls) the path does need to be specified.
At test program:
#include <unistd.h>
#include <stdio.h>
/* This should list the current working directory. */
int main(void)
{
execl("/bin/ls", "ls", "-al", "-rt", (char*) 0);
perror("execl() failed");
return 0;
}
The simplest way to lose sight of the sh -c entries is:
sprintf(cmd, "exec ./test %s", argum);
The exec replaces the shell run by system() with the command, instead of having the shell hang around until the ./test process terminates.
The alternative is outlined by alk in his answer — use the exec*() family of functions (system calls).