2
#define _GNU_SOURCE  
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void func();
void main(int argc,char **argv)
{
    printf("i am main\n");
    int clone_flag,arg,retval;
    char *stack;
    clone_flag=CLONE_VM|CLONE_SIGHAND;
    stack=(char*)malloc(4096);
    retval=clone((void*)func,&(stack[4095]),clone_flag,NULL);
    stack=(char*)malloc(4096);
    retval=clone((void*)func,&(stack[4095]),clone_flag,NULL); 
}
void func()
{
    int i;
    for(i=0;i<3;i++)
    {
    printf("i: %d\n ",i);
    }
}

output:

i am main
i: 0   
i: 1

strace -f

5915  fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(4, 1), ...}) = 0
5915  ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
5915  brk(NULL)                         = 0xaf2000
5915  brk(0xb14000)                     = 0xb14000
5915  write(1, "i am main\n", 10)       = 10
5915  clone(child_stack=0xaf400f, flags=CLONE_VM|CLONE_SIGHAND) = 5916
5915  clone(child_stack=0xaf501f, flags=CLONE_VM|CLONE_SIGHAND) = 5917
5915  exit_group(5917)                  = ?
5915  +++ exited with 29 +++
5917  write(1, "i", 1)                  = 1
5917  write(1, ": 0\n ", 5)             = 5
5917  write(1, "i", 1)                  = 1
5917  write(1, ": 1\n ", 5)             = 5
5916  --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xaf194f} ---
5916  +++ killed by SIGSEGV (core dumped) +++
5917  +++ killed by SIGSEGV +++

gdb ./a.out core

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  buffered_vfprintf (s=0x7f737fd43620 <_IO_2_1_stdout_>, 
    format=0x40074e "i: %d\n ", args=0x1f49f27) at vfprintf.c:2299
2299    vfprintf.c: No such file or directory.
[Current thread is 1 (LWP 6280)]
(gdb) where
#0  buffered_vfprintf (s=0x7f737fd43620 <_IO_2_1_stdout_>, 
    format=0x40074e "i: %d\n ", args=0x1f49f27) at vfprintf.c:2299
#1  0x00007f737f9cb32d in _IO_vfprintf_internal (
    s=0x7f737fd43620 <_IO_2_1_stdout_>, format=0x40074e "i: %d\n ", 
    ap=ap@entry=0x1f49f27) at vfprintf.c:1293
#2  0x00007f737f9d3899 in __printf (format=<optimized out>) at printf.c:33
#3  0x00000000004006a8 in func () at code.c:23
#4  0x00007f737fa8541d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

it is confusing if I remove the"printf("i am main\n");" the code will run well

strace

5937  brk(NULL)                         = 0x1f75000
5937  brk(0x1f97000)                    = 0x1f97000
5937  clone(child_stack=0x1f75fff, flags=CLONE_VM|CLONE_SIGHAND) = 5938
5937  clone(child_stack=0x1f7700f, flags=CLONE_VM|CLONE_SIGHAND) = 5939
5937  exit_group(5939)                  = ?
5937  +++ exited with 51 +++
5939  fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(4, 1), ...}) = 0
5939  ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
5939  write(1, "i: 0\n", 5)             = 5
5939  write(1, " i: 1\n", 6)            = 6
5939  write(1, " i: 2\n", 6)            = 6
5938  write(1, " i: 2\ni: 0\n", 11)     = 11
5939  exit_group(6)                     = ?
5939  +++ exited with 6 +++
5938  write(1, " i: 1\n", 6)            = 6
5938  write(1, " i: 2\n", 6)            = 6
5938  exit_group(6)                     = ?
5938  +++ exited with 6 +++

why the "printf" makes such a big difference?(by the way,why the SIGSEGV killed another process?)

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
qiu
  • 21
  • 3
  • `&(stack[4095])` is probably misaligned for use as a stack pointer. Try it with `&(stack[4096])` instead. – Ian Abbott Nov 06 '19 at 14:39
  • 1
    Does this answer your question? [segfault with clone() and printf](https://stackoverflow.com/questions/38067026/segfault-with-clone-and-printf) – Sander De Dycker Nov 06 '19 at 14:41
  • Are you sure you need `clone` ? Why not `pthread_create` or `fork` ? – Sander De Dycker Nov 06 '19 at 14:43
  • Also : the signature should be `int func(void*)`, not `void func()`. – Sander De Dycker Nov 06 '19 at 14:46
  • ... the default stdio buffer size is 8192 bytes in my machine ... i had been making a stack less than 4096 ok before i started using printf ... unbuffering it at first had opposite effect that wanted, so then i setvbuf with buffer i allocated of 256 bytes with line buffering ( setvbuf ( stdout , _buffer_ , _IOLBF , 128 ) ) and then all was ok with a small stack for each CLONE_VM and short printf lines ... – sol Dec 16 '22 at 22:40

1 Answers1

5

Your call to printf is overflowing the available stack. 4096 bytes isn't enough for all it needs to do. To confirm, here's a sample gdb session:

Reading symbols from ./a.out...done.
(gdb) break 14
Breakpoint 1 at 0x400624: file source.c, line 14.
(gdb) break 16
Breakpoint 2 at 0x400659: file source.c, line 16.
(gdb) break func
Breakpoint 3 at 0x40068b: file source.c, line 21.
(gdb) run
Starting program: a.out 
i am main

Breakpoint 1, main (argc=1, argv=0x7fffffffe3a8) at source.c:14
14      retval=clone((void*)func,&(stack[4095]),clone_flag,NULL);
(gdb) print/x stack
$1 = 0x602420
(gdb) cont
Continuing.
[New LWP 25381]
[Switching to LWP 25381]

Thread 2 hit Breakpoint 3, func () at source.c:21
21      for(i=0;i<3;i++)
(gdb) print/x &i
$2 = 0x60340b
(gdb) watch $rsp < 0x602420 
Watchpoint 4: $rsp < 0x602420

I've asked gdb to stop when the stack pointer ($rsp on x86-64 machines; you may need a different register according to your CPU) falls below the start of the allocated stack range.

(gdb) cont
Continuing.
[Switching to LWP 25375]

Thread 1 "a.out" hit Breakpoint 2, main (argc=1, argv=0x7fffffffe3a8) at source.c:16
16      retval=clone((void*)func,&(stack[4095]),clone_flag,NULL);
(gdb) print/x stack
$3 = 0x603430
(gdb) cont
Continuing.
[New LWP 25383]
[Switching to LWP 25383]

Thread 3 hit Breakpoint 3, func () at source.c:21
21      for(i=0;i<3;i++)
(gdb) cont
Continuing.
[Switching to LWP 25381]

Thread 2 hit Watchpoint 4: $rsp < 0x602420

Old value = 0 
New value = 1
buffered_vfprintf (s=0x7ffff7dd2620 <_IO_2_1_stdout_>, format=0x40074e "i: %d\n ", args=0x603327) at vfprintf.c:2295
2295        vfprintf.c: No such file or directory.
(gdb) where
#0  buffered_vfprintf (s=0x7ffff7dd2620 <_IO_2_1_stdout_>, format=0x40074e "i: %d\n ", args=0x603327) at vfprintf.c:2295
#1  0x00007ffff7a5a32d in _IO_vfprintf_internal (s=0x7ffff7dd2620 <_IO_2_1_stdout_>, format=0x40074e "i: %d\n ",
    ap=ap@entry=0x603327) at vfprintf.c:1293
#2  0x00007ffff7a62899 in __printf (format=<optimised out>) at printf.c:33
#3  0x00000000004006a8 in func () at source.c:23
#4  0x00007ffff7b1441d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

We can now see that the stack pointer has gone well below the stack range allocated.

(gdb) print/x $rsp
$4 = 0x600c4f

Regarding what difference the printf makes, you could compare execution traces (generated using a simple si loop). I found that they first diverge at this test:

   if (UNBUFFERED_P (s))
     /* Use a helper function which will allocate a local temporary buffer
        for the stream and then call us again.  */
     return buffered_vfprintf (s, format, ap, mode_flags);

It appears that the earlier call to printf has changed the mode of stdout to "unbuffered", so the later printf needs to go deeper to work with it. You could reproduce this by replacing the first printf with setbuf(stdout,NULL).

However, the real question isn't why printf makes a difference, it's "How Did That Ever Work?". There are three processes, two of which are being careless with the memory space they all share, so if and when they break is down to timing.

JigglyNaga
  • 151
  • 5
  • It works when l enlarge the stack's size.But go back to the question,why does the child process's printf will in the stack range when the calling process don't printf? – qiu Nov 07 '19 at 08:17
  • When I tried without the early `printf`, I got inconsistent results -- it would still sometimes give incomplete output. So the early `printf` isn't what's causing the problem, it just makes it more likely. – JigglyNaga Nov 07 '19 at 13:11