2
votes

In execve function, arguments are passed by a pointer array. If these pointers ponit to memory in the previous stack, can these memory still be accessed in a new process image.

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    char filename[20] = "a.out";
    char str[20] = "hello\n";
    char *argv[3];

    argv[0] = filename;
    argv[1] = str;
    argv[2] = NULL;
    execve("/hel/a.out", argv, NULL);
    return 0;
}

/*   /hel/a.out code   */
#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
    printf("%s\n", argv[1]);  /** Here, should the memory pointed by argv[1]
                               *  be freed after execve  has been called?
                               */ 
    return 0;
}
1
You really should use straceBasile Starynkevitch
Yeah.I put your trace code in main, and the output is a bit complicated. I'm learning Advanced Programming in the UNIX Environment and want to finish it to gain a global concept. After that, maybe It's time for studying every detail.hel
Perhaps I get it. If a=13; (high byte 00, low byte 0d) argv[1] = (char *)(&a); In the second main,correctly output format like: printf("%s", argv[1]); // print '\n' Copy only the argument and environment strings to new locations in execve. I don't know whether I'm right or not. Thanks for all the answers and I'll study it deeply afterwards.hel

1 Answers

5
votes

Read carefully the documentation of execve(2) (and also Advanced Linux Programming to get a broader view). Read about virtual memory, paging, MMUs, processes.

The execve system call is installing a fresh new virtual address space in your process (so the old virtual address space of the program doing execve successfully disappears, being overwritten by the new one), so you don't share any data with the previous one (and a successful execve does not return, since the new program is started). Your new program would be able to later change the virtual address space, e.g. with mmap(2)...

The address of argv strings in the new virtual address space are independent of the address of arguments to execve; the string contents are the same. No data is shared between the old virtual address space and the new one, but arguments to the new program (and program environment) are copied. Read also about ASLR

The arguments of execve are strings copied (with their copy being pushed) on the new fresh call stack of the new virtual address space for its starting function (_start in crt0 which calls main). Of course you should not free any argv[i] - that would be undefined behavior.

Hence int a; argv[1]=(char*)&a; ... execve with argv, is undefined behavior, because you cannot guarantee that the memory zone at the address of a is a proper null-terminated string. Read about endianness & ABI.

So execve wants a NULL terminated array argv of proper strings (not arbitrary pointers), and another NULL terminated env array of strings, and each string should be terminated by a zero byte. There is a rather small limit ARG_MAX (typically 128Kbytes) on the total memory space copied from the old address space to the new one thru argv & env.

You might perhaps use shared memory (see shm_overview(7)) to share memory between various processes (and you'll synchronize with semaphores, see sem_overview(7)...); but you often would prefer other inter-process communication techniques (e.g. pipe(7)-s, fifo(7)-s, socket(7)-s, etc...).

BTW, use also strace(1) to understand which system calls are involved by your program, and use proc(5), notably by running cat /proc/$$/maps and cat /proc/$pidofyourprogram/maps to understand more about virtual address space.

You could even put in both of your main functions (before execve in the first one, before return 0; the second one) something like

 char cmd[64];
 snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/maps", (int)getpid());
 printf("before running %s\n", cmd);
 fflush(NULL);
 int err = system(cmd);
 if (err) fprintf(stderr, "system failed err=%d\n", err);
 else printf("system %s done\n", cmd);

This will show you a view of the virtual address space. Of course, a more serious program should fopen a /proc/1234/maps file and loop on fgets to read every line until EOF then fclose.

Be patient, read all the references here, and take time to learn more about POSIX programming. Studying some free software source code (e.g. on http://github.com/ you can chose some interesting projects...) and contributing to them should be worthwhile.