Calling main twice behaves differently - linux

I have the following code which is supposed the call the main function twice.
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <limits.h>
#include <link.h>
#include <stdio.h>
#include <time.h>
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>
#include <unistd.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/mman.h>
extern char** environ;
static int (*main_orig)(
int,
char**,
char**
);
static int (*__libc_start_main_orig)(
int (*)(int, char**, char**),
int,
char**,
int (*)(int, char**, char**),
void (*)(void),
void (*)(void),
void*
);
static int (*init_orig)(
int,
char**,
char**
);
static void (*fini_orig)(void);
static void (*rtld_fini_orig)(void);
static void* stack_end_orig;
static char* libs[] = {
"libpthread-2.22.so",
NULL
};
static void my_dlopen(char* lib_name)
{
int ret;
struct timespec before;
struct timespec after;
long long dl_time;
void* handle = NULL;
(void) clock_gettime(CLOCK_MONOTONIC, &before);
handle = dlopen(lib_name, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
if (handle == NULL) {
fprintf(stdout, "%-35s :: dlopen failed with %s :: ", lib_name, dlerror());
}
else {
fprintf(stdout, "%-35s :: dlopen [OK] :: ", lib_name);
ret = dlclose(handle);
if (ret != 0) {
fprintf(stdout, "dlclose failed with %s :: ", dlerror());
}
else {
fprintf(stdout, "dlclose [OK] :: ");
}
}
(void) clock_gettime(CLOCK_MONOTONIC, &after);
dl_time = ((long long) (after.tv_sec - before.tv_sec)) * 1000000000ll +
((long long) (after.tv_nsec - before.tv_nsec));
fprintf(stdout, "%12lld us\n", dl_time / 1000ll);
}
static int my_main(int argc, char** argv, char** envp)
{
int i;
int ret;
fprintf(stdout, "--- Before main --- %d :: %d :: %p\n", getpid(), getppid(), main_orig);
for (i = 0; argv[i] != NULL; i++) {
fprintf(stdout, "argv[%2d] = %s\n", i, argv[i]);
}
for (i = 0; envp[i] != NULL; i++) {
fprintf(stdout, "envp[%2d] = %s\n", i, envp[i]);
}
ret = main_orig(argc, argv, envp);
fprintf(stdout, "--- After main --- %d :: %d :: %p\n", getpid(), getppid(), main_orig);
return ret;
}
int main_hook(int argc, char** argv, char** envp)
{
int i;
int ret;
struct timespec before;
struct timespec after;
long long dl_time;
void* dummy_buffer = NULL;
const size_t dummy_size = 256 * 1024 * 1024;
asm volatile("": : :"memory");
fprintf(stdout, "****************************************************\n");
ret = mlockall(MCL_CURRENT | MCL_FUTURE);
if (ret == -1) {
fprintf(stdout, "mlockall failed with errno = %d\n", errno);
}
else {
fprintf(stdout, "mlockall [OK]\n");
}
ret = mallopt(M_TRIM_THRESHOLD, -1);
if (ret == 1) {
fprintf(stdout, "mallopt(M_TRIM_THRESHOLD, -1) [OK]\n");
}
else {
fprintf(stdout, "mallopt(M_TRIM_THRESHOLD, -1) [!!]\n");
}
ret = mallopt(M_MMAP_MAX, 0);
if (ret == 1) {
fprintf(stdout, "mallopt(M_MMAP_MAX, 0) [OK]\n");
}
else {
fprintf(stdout, "mallopt(M_MMAP_MAX, 0) [!!]\n");
}
dummy_buffer = malloc(dummy_size);
if (dummy_buffer != NULL) {
fprintf(stdout, "dummy_buffer = %p :: %zu\n", dummy_buffer, dummy_size);
memset(dummy_buffer, 0x00, dummy_size);
free(dummy_buffer);
}
asm volatile("": : :"memory");
fprintf(stdout, "****************************************************\n");
(void) clock_gettime(CLOCK_MONOTONIC, &before);
for (i = 0; libs[i] != NULL; i++) {
my_dlopen(libs[i]);
}
(void) clock_gettime(CLOCK_MONOTONIC, &after);
dl_time = ((long long) (after.tv_sec - before.tv_sec)) * 1000000000ll +
((long long) (after.tv_nsec - before.tv_nsec));
fprintf(stdout, "****************************************************\n");
fprintf(stdout, "Total dlopen time = %lld ms\n", dl_time / 1000000ll);
asm volatile("": : :"memory");
fprintf(stdout, "****************************************************\n");
ret = 0;
ret += my_main(argc, argv, envp);
ret += my_main(argc, argv, envp);
return ret;
}
int __libc_start_main( int (*main)(int, char**, char**),
int argc,
char** argv,
int (*init)(int, char**, char**),
void (*fini)(void),
void (*rtld_fini)(void),
void* stack_end)
{
int i;
int ret;
for (i = 0; environ[i] != NULL; i++) {
char* substr = strstr(environ[i], "LD_PRELOAD=");
if (substr != NULL) {
fprintf(stdout, "%s found and replaced with ", environ[i]);
memset(&environ[i][0], 'x', strlen(environ[i]));
}
fprintf(stdout, "%s\n", environ[i]);
}
__libc_start_main_orig = dlsym(RTLD_NEXT, "__libc_start_main");
main_orig = main;
init_orig = init;
fini_orig = fini;
rtld_fini_orig = rtld_fini;
stack_end_orig = stack_end;
ret = __libc_start_main_orig(main_hook, argc, argv, init, fini, rtld_fini, stack_end);
return ret;
}
This code is compiled as shared library with:
$CC -ggdb -fPIC -shared replace_main.c -o replace_main -ldl -lrt -pthread.
I use the so file like this:
LD_PRELOAD=/var/log/replace_main ls -l /
which gives me:
LD_PRELOAD=/var/log/replace_main found and replaced with xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TERM=xterm-256color
SHELL=/bin/sh
SSH_CLIENT=xxxxxxxxx
OLDPWD=/var/log
SSH_TTY=/dev/pts/0
USER=root
LD_LIBRARY_PATH=xxxxxxxxx
MAIL=/var/mail/root
PATH=xxxxxxxxx
LTTNG_UST_CLOCK_PLUGIN=xxxxxxxxx
LTTNG_UST_WITHOUT_BADDR_STATEDUMP=xxxxxxxxx
PWD=/var/log
EDITOR=vi
TZ=UTC
PS1=\u#\h:\w\$
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=xxxxxxxxx
_=/bin/ls
****************************************************
mlockall [OK]
mallopt(M_TRIM_THRESHOLD, -1) [OK]
mallopt(M_MMAP_MAX, 0) [OK]
dummy_buffer = 0x5a4020 :: 268435456
****************************************************
libpthread-2.22.so :: dlopen [OK] :: dlclose [OK] :: 596 us
****************************************************
Total dlopen time = 0 ms
****************************************************
--- Before main --- 25870 :: 3265 :: 0x12068
argv[ 0] = ls
argv[ 1] = -l
argv[ 2] = /
envp[ 0] = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
envp[ 1] = TERM=xterm-256color
envp[ 2] = SHELL=/bin/sh
envp[ 3] = SSH_CLIENT=xxxxxxxxx
envp[ 4] = OLDPWD=/var/log
envp[ 5] = SSH_TTY=/dev/pts/0
envp[ 6] = USER=root
envp[ 7] = LD_LIBRARY_PATH=xxxxxxxxx
envp[ 8] = MAIL=/var/mail/root
envp[ 9] = PATH=xxxxxxxxx
envp[10] = LTTNG_UST_CLOCK_PLUGIN=xxxxxxxxx
envp[11] = LTTNG_UST_WITHOUT_BADDR_STATEDUMP=xxxxxxxxx
envp[12] = PWD=/var/log
envp[13] = EDITOR=vi
envp[14] = TZ=UTC
envp[15] = PS1=\u#\h:\w\$
envp[16] = SHLVL=1
envp[17] = HOME=/root
envp[18] = LOGNAME=root
envp[19] = SSH_CONNECTION=xxxxxxxxx
envp[20] = _=/bin/ls
total 19
drwxr-xr-x 2 root root 6176 Jul 17 2018 bin
drwxr-xr-x 2 root root 3 Jul 17 2018 boot
-rw-rw-r-- 1 sirpa tracing 2447 Jul 17 2018 cxp9025851_3.xml
drwxr-xr-x 8 root root 8300 Apr 24 11:48 dev
drwxr-xr-x 38 root root 1584 Jul 17 2018 etc
drwxr-xr-x 3 root root 28 Jul 17 2018 home
drwxr-xr-x 8 root root 5263 Jul 17 2018 lib
-rwxr-xr-x 1 root root 509 Apr 25 2018 linuxrc.sh
drwxr-xr-x 2 root root 3 Apr 22 2018 media
drwxr-xr-x 2 root root 3 Apr 22 2018 mnt
drwxr-xr-x 8 root root 115 Jul 17 2018 opt
dr-xr-xr-x 759 root root 0 Jan 1 1970 proc
drwxrwxrwx 28 sirpa users 4096 Apr 23 17:51 rcs
drwxr-xr-x 2 root root 3 Apr 22 2018 root
drwxrwxrwt 12 root root 540 Apr 24 11:49 run
drwxr-xr-x 2 root root 2868 Jul 17 2018 sbin
drwxr-xr-x 53 root root 12288 Apr 24 10:39 software
dr-xr-xr-x 12 root root 0 Apr 24 11:48 sys
drwxrwxrwt 10 root root 740 Apr 24 12:49 tmp
drwxr-xr-x 10 root root 150 Apr 22 2018 usr
drwxr-xr-x 13 root root 186 Jul 17 2018 var
--- After main --- 25870 :: 3265 :: 0x12068
--- Before main --- 25870 :: 3265 :: 0x12068
argv[ 0] = ls
argv[ 1] = -l
argv[ 2] = /
envp[ 0] = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
envp[ 1] = TERM=xterm-256color
envp[ 2] = SHELL=/bin/sh
envp[ 3] = SSH_CLIENT=xxxxxxxxx
envp[ 4] = OLDPWD=/var/log
envp[ 5] = SSH_TTY=/dev/pts/0
envp[ 6] = USER=root
envp[ 7] = LD_LIBRARY_PATH=xxxxxxxxx
envp[ 8] = MAIL=/var/mail/root
envp[ 9] = PATH=xxxxxxxxx
envp[10] = LTTNG_UST_CLOCK_PLUGIN=xxxxxxxxx
envp[11] = LTTNG_UST_WITHOUT_BADDR_STATEDUMP=xxxxxxxxx
envp[12] = PWD=/var/log
envp[13] = EDITOR=vi
envp[14] = TZ=UTC
envp[15] = PS1=\u#\h:\w\$
envp[16] = SHLVL=1
envp[17] = HOME=/root
envp[18] = LOGNAME=root
envp[19] = SSH_CONNECTION=xxxxxxxxx
envp[20] = _=/bin/ls
bin boot cxp9025851_3.xml dev etc home lib linuxrc.sh media mnt opt proc rcs root run sbin software sys tmp usr var
--- After main --- 25870 :: 3265 :: 0x12068
root#du1:/var/log#
As you can see the ls's main is called twice but the second time it seems that the -l argument is ignored. What can the cause?
PS: I am running the code on ARM Linux variant with kernel 4.1
Thanks,

What can the cause?
The option parsing library has internal state, and you are not resetting that state.
From man 3 getopt:
extern int optind, ...
The variable optind is the index of the next element to be processed in argv.
The system initializes this value to 1. The caller can reset it to 1 to restart
scanning of the same argv, or when scanning a new argument vector.
Since you are not resetting optind inside /bin/ls to 1, when the real main calls getopt, it immediately gets a "no more options" answer.
This can be demonstrated with a trivial program:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int rc;
while ((rc = getopt(argc, argv, "abc")) != -1) {
printf("getopt: '%c'\n", rc);
}
return 0;
}
gcc main.c -o main
LD_PRELOAD=./replace_main.so ./main -ab
...
--- Before main --- 34822 :: 14915 :: 0x55ce59e2768a
argv[ 0] = ./main
argv[ 1] = -ab
getopt: 'a'
getopt: 'b'
--- After main --- 34822 :: 14915 :: 0x55ce59e2768a
--- Before main --- 34822 :: 14915 :: 0x55ce59e2768a
argv[ 0] = ./main
argv[ 1] = -ab
--- After main --- 34822 :: 14915 :: 0x55ce59e2768a
Note that getopt lines are missing from the second invocation (just as one would expect).
If I add optind = 1; before the while loop in main.c, then it starts working as you expect:
--- Before main --- 35487 :: 14915 :: 0x55939fb706ca
argv[ 0] = ./main
argv[ 1] = -ab
getopt: 'a'
getopt: 'b'
--- After main --- 35487 :: 14915 :: 0x55939fb706ca
--- Before main --- 35487 :: 14915 :: 0x55939fb706ca
argv[ 0] = ./main
argv[ 1] = -ab
getopt: 'a'
getopt: 'b'
--- After main --- 35487 :: 14915 :: 0x55939fb706ca

Related

syscall lseek() is slower in ubuntu 2.6.32 vs 2.6.24

I am running the following code on ubuntu 14 and 18. It is 6X slower on 18 on same hardware. Is there something I am doing wrong?
main(int argc, char *argv[])
{
int fd;
off_t m;
time_t start, ed;
int i, k;
if (argc<2) exit(0);
fd = open(argv[1],O_RDWR|O_CREAT);
if (fd<0) {
printf("cannot open file %s\n", argv[1]);
exit(0);
}
start = time(0L);
for(k=0; k<100; ++k) {
for(i=0;i<500000;++i) {
m = lseek(fd, 0, 0);
if (m== -1) {
printf("lseek failed\n");
exit(0);
}
}
}
ed = time(0L);
printf("Time: %ld\n",ed-start);
}
On ubuntu 14 this takes 4 seconds
On ubuntu 18 it takes 24 seconds
Hardware is same
zx485 was right. the Spectre prevention in kernel was slowing it down by a factor of 6.
Disabling the protection with the following on redhat 7 changed it to normal.
# echo 0 > /sys/kernel/debug/x86/pti_enabled
# echo 0 > /sys/kernel/debug/x86/retp_enabled
# echo 0 > /sys/kernel/debug/x86/ibrs_enabled

Only one thread created with MPI & no speed-up with OpenMP

I actually have two questions but it seems they may be connected:
1) I've tried to run basic MPI example:
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf("I am %d from %d\n", rank, size);
MPI_Finalize();
return 0;
}
It has to output something like:
I am 0 from 2
I am 1 from 2
Although I'm getting the following:
$ mpicc mpi_hello.c -o hello
$ mpirun -np 4 ./hello
I am 0 from 1
I am 0 from 1
I am 0 from 1
I am 0 from 1
$ mpirun -np 2 ./hello
I am 0 from 1
I am 0 from 1
Is it somehow connected to thread definition in Linux? I'm running it on Ubuntu 16.04.
2) My OpenMP program:
#include <omp.h>
#include <math.h>
#include <time.h>
#include <iostream>
#include <stdio.h>
const int N = 10000;
int matrix[N][N];
int main()
{
#pragma omp parallel num_threads(2)
#pragma omp for
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
matrix[i][j] = 1+i;
clock_t t;
t = clock();
#pragma omp parallel num_threads(2)
#pragma omp for
for (int i = 0; i < N; i++)
{
matrix[i][i] = 0;
for (int j = 0; j< N; j++)
if (j != i)
matrix[i][i] += sin(cos(log(matrix[i][j] + matrix[j][i])));
}
t = clock() - t;
std::cout << "It took " << ((float)t)/CLOCKS_PER_SEC << " sec" << std::endl;
return 0;
}
It works correctly and uses 2 threads. However, it loads 2 processors (~100% CPU) and takes the same time (~34 seconds) as the similiar consequtive one (loads 1 processor ~50% CPU). I know that OpenMP may need some time to start, but how can it result in the same duration of programs?
Answering to the MPI part of the question.
Do you have MPICH installed? If is that so, try to compile and run like this:
$ mpicc.mpich mpi_hello.c -o hello
$ mpirun.mpich -np 4 ./hello
I am 0 from 4
I am 1 from 4
I am 2 from 4
I am 3 from 4
It should work.

second shm_open() fails with ENOENT

mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
shm_fd = shm_open("/ipc_shm", O_CREAT | O_RDWR, mode);
This works, returns 4 for shm_fd. The same process then calls a library function that also calls
fd = shm_open("/ipc_shm", O_RDWR, 0);
This one fails with errno set to 2, i.e. ENOENT (No such file or directory). There is no shm_unlink call in the middle. Any idea why the second call is failing. Appreciate your help.
my test.c:
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int main (int argc, char *argv[])
{
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
int shm_fd = shm_open("/ipc_shm", O_CREAT | O_RDWR, mode);
int fd = shm_open("/ipc_shm", O_RDWR, 0);
return 0;
}
compiled with gcc test.c -Wall -lrt works as expected:
$strace ./a.out
....
statfs("/dev/shm/", {f_type=0x1021994, f_bsize=4096, f_blocks=22290, f_bfree=22290, f_bavail=22290, f_files=55725, f_ffree=55723, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
futex(0xb6f5d1c0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/dev/shm/ipc_shm", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0777) = 3
fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
open("/dev/shm/ipc_shm", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = 4
exit_group(0)
Please run strace on your application, and search for all occurrences of ipc, and maybe chroot(). Maybe something unlinks the file?

Execute a command in another terminal via /dev/pts

I have a terminal that uses STDIN 3 (/proc/xxxx/fd/0 -> /dev/pts/3)
So if (in another terminal) I do:
echo 'do_something_command' > /dev/pts/3
The command is shown in my first (pts/3) terminal, but the command is not executed. And if (in this terminal pts/3) I'm in a program waiting for some data from stdin, the data is written on screen but the program does not capture it from stdin.
What I want to do is execute the command "do_something_command" and not only show it.
Can someone explain this behavior to me? How do I achieve my intention?
I completely get what you are asking. You can achieve this by writing and executing a small piece of code in C yourself. This should give you some idea.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
void print_help(char *prog_name) {
printf("Usage: %s [-n] DEVNAME COMMAND\n", prog_name);
printf("Usage: '-n' is an optional argument if you want to push a new line at the end of the text\n");
printf("Usage: Will require 'sudo' to run if the executable is not setuid root\n");
exit(1);
}
int main (int argc, char *argv[]) {
char *cmd, *nl = "\n";
int i, fd;
int devno, commandno, newline;
int mem_len;
devno = 1; commandno = 2; newline = 0;
if (argc < 3) {
print_help(argv[0]);
}
if (argc > 3 && argv[1][0] == '-' && argv[1][1] == 'n') {
devno = 2; commandno = 3; newline=1;
} else if (argc > 3 && argv[1][0] == '-' && argv[1][1] != 'n') {
printf("Invalid Option\n");
print_help(argv[0]);
}
fd = open(argv[devno],O_RDWR);
if(fd == -1) {
perror("open DEVICE");
exit(1);
}
mem_len = 0;
for (i = commandno; i < argc; i++) {
mem_len += strlen(argv[i]) + 2;
if (i > commandno) {
cmd = (char *)realloc((void *)cmd, mem_len);
} else { // i == commandno
cmd = (char *)malloc(mem_len);
}
strcat(cmd, argv[i]);
strcat(cmd, " ");
}
if (newline == 0)
usleep(225000);
for (i = 0; cmd[i]; i++)
ioctl (fd, TIOCSTI, cmd+i);
if (newline == 1)
ioctl (fd, TIOCSTI, nl);
close(fd);
free((void *)cmd);
exit (0);
}
Compile and execute it with sudo permissions. For example, if you want to execute a command on /dev/pts/3, then simply do a sudo ./a.out -n /dev/pts/3 whoami, runs a whoami on /dev/pts/3.
This code was completely taken from this page.
You seem to use the wrong quotes around the command.
Either remove the quotes and the echo command, or use echo and back-ticks (`).
Try:
echo `date` > /dev/pts/3
or just
date > /dev/pts/3
Note that whatever runs on /dev/pts/3 wouldn't be able to read what pops up "from behind".

Issues regarding mutexes on POSIX threads

I'm having some issues with the following code. I just can't seem to find the bug:
1 #include <pthread.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 struct bla
7 {
8 pthread_mutex_t mut;
9 int x;
10 };
11
12
13 pthread_t tid;
14
15 void *thr_fn1 (struct bla *fp);
16
17 int main()
18 {
19 struct bla *fp;
20 fp = (struct bla *) malloc (sizeof(struct bla));
21 fp->x=3;
22 printf ("Initializing mutex_init\n");
23 pthread_mutex_init (&fp->mut,NULL);
24 pthread_create (&tid,NULL,thr_fn1,fp);
25 sleep (2);
26 printf ("Main thread ended sleep. Incrementing.\n");
27 fp->x++;
28 pthread_join (tid,NULL);
29 printf ("x=%d\n",fp->x);
30 pthread_mutex_destroy(&fp->mut);
31 return 0;
32
33 }
34
35 void *thr_fn1 (struct bla *fp)
36 {
37 printf ("Locking new thread!\n");
38 pthread_mutex_lock (&fp->mut);
39 printf ("Sleeping.\n");
40 sleep (5);
41 pthread_mutex_unlock (&fp->mut);
42 printf ("Thread unlocked.\n");
43 return ((void *) 0);
44 }
Why does the value still get incremented at line 27? Shouldn't it be protected by the mutex in the second thread by the lock (line 38)?
Thanks!
There is no automatic association between mutexes and data. If you want a mutex to protect some particular set of data, you are responsible for locking and unlocking the mutex around accesses to that data:
sleep (2);
pthread_mutex_lock(&fp->mut);
printf ("Main thread ended sleep. Incrementing.\n");
fp->x++;
pthread_mutex_unlock(&fp->mut);

Resources