Portable way to programatically detect where a signal occured - c

Assuming the following code (main.c):
#include <unistd.h>
#include <signal.h>
void handler(int sig)
{
pause(); /* line 7 */
}
int main(void)
{
signal(SIGALRM, handler);
alarm(1);
pause();
}
When I run this in gbd and set a break point inside handler(), run the code and wait a second I can do the following:
(gdb) b 7
Breakpoint 1 at 0x4005b7: file main.c, line 7.
(gdb) r
Starting program: a.out
Breakpoint 1, handler (sig=14) at main.c:7
7 pause();
(gdb) bt
#0 handler (sig=14) at main.c:7
#1 <signal handler called>
#2 0x00007ffff7afd410 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82
#3 0x00000000004005e0 in main () at main.c:14
Is there a portable way to get 0x00007ffff7afd410 or 0x00000000004005e0?

With sigaction instead of signal the handler is called with the ucontext of the location where the signal occurred:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
static void handler(int sig, siginfo_t *siginfo, void *context)
{
ucontext_t *ucontext = context;
printf("rip %p\n", (void *)ucontext->uc_mcontext.gregs[REG_RIP]);
pause();
}
int main(void)
{
struct sigaction sact;
memset(&sact, 0, sizeof sact);
sact.sa_sigaction = handler;
sact.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &sact, NULL) < 0) {
perror("sigaction");
return 1;
}
alarm(1);
pause();
return 0;
}
rip output and gdb bt output:
(gdb) b 13
Breakpoint 1 at 0x4006de: file main.c, line 13.
(gdb) r
Starting program: /home/osboxes/a.out
rip 0x7ffff7ae28a0
Breakpoint 1, handler (sig=14, siginfo=0x7fffffffdf70, context=0x7fffffffde40)
at main.c:13
13 pause();
(gdb) bt
#0 handler (sig=14, siginfo=0x7fffffffdf70, context=0x7fffffffde40)
at main.c:13
#1 <signal handler called>
#2 0x00007ffff7ae28a0 in __pause_nocancel () from /lib64/libc.so.6
#3 0x0000000000400758 in main () at main.c:28

Not extremely portable I guess, but backtrace(3) is available in glibc and a few other libc's:
backtrace() returns a backtrace for the calling program, in the array
pointed to by buffer. A backtrace is the series of currently active
function calls for the program.
You'd have to check how many entries up the stack you need to look. It should be consistent for Linux at least.
If you want to translate the backtrace to something resembling gdb's display, you could use addr2line(1) from binutils. With something like
popen("addr2line -Cfip -e ./myprog", "w")
you could even do it at runtime by writing addresses (as strings) to the FILE* you get back.

Related

How get output of address sanitizer when emiting SIGINT to halt a loop

When I compile this simple test program I get the obvious leak report from address sanitizer, but when I compile the same program but with a infinite loop, and break it emitting SIGINT I don't get any output.
Checking asm output, the malloc is not optimized away (if this is possible at all)
Is this the expected behavior of address sanitizer? I don't encounter this problem in other developments.
Working example:
#include <stdlib.h>
int main(void)
{
char *a = malloc(1024);
return 1;
}
Not working (kill with SIGINT):
#include <stdlib.h>
int main(void)
{
char *a = malloc(1024);
for(;;);
return 1;
}
compile: gcc test.c -o test -fsanitize=address
I encounter this problem in a full programm but I reduced it to this minimal example.
I tried many ways, with exit() and abort() calls, this works:
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuf;
void handler (int signum) {
printf("handler %d \n", signum);
// we jump from here to main()
// and then call return
longjmp(jmpbuf, 1);
}
int main(int argc, char *argv[])
{
if (setjmp(jmpbuf)) {
// we are in signal context here
return 2;
}
signal(SIGINT, handler);
signal(SIGTERM, handler);
char *a = malloc(1024);
while (argc - 1);
return 1;
}
Results in:
> gcc file.c -fsanitize=address && timeout 1 ./a.out arg
handler 15
=================================================================
==12970==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 1 object(s) allocated from:
#0 0x7f4798c9bd99 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:86
#1 0x5569e64e0acd in main (/tmp/a.out+0xacd)
#2 0x7f479881206a in __libc_start_main (/usr/lib/libc.so.6+0x2306a)
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).
I guess that the address sanitizer function are executed after main returns.
The code responsible for printing that error output is called as a destructor (fini) procedure. Since your program terminates without calling any of the process destructors (due to the SIGINT), you do not get any error printouts.
__lsan_do_leak_check() can help you avoid using longjmp in #KamilCuk's answer:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sanitizer/lsan_interface.h>
void handler (int signum) {
__lsan_do_leak_check();
}
int main(int argc, char *argv[])
{
signal(SIGINT, handler);
char *a = malloc(1024);
a=0;
printf("lost pointer\n");
for(;;);
return 1;
}
Demo:
clang test.c -fsanitize=address -fno-omit-frame-pointer -g -O0 -o test && ./test
lost pointer
C-c C-c
=================================================================
==29365==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 1 object(s) allocated from:
#0 0x4c9ca3 in malloc (/home/bjacob/test+0x4c9ca3)
#1 0x4f9187 in main /home/bjacob/test.c:13:14
#2 0x7fbc9898409a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).
Note I added a=0 to create a leak.
I also added a printf. Without that printf, the leak error is not printed. I suspect the compiler optimized-out the use of the variable "a" despite my using the -O0 compiler option.

Using a function pointer to pthread_create causes segfault

I am attempting to stub out pthread_create to be able to fully unit test a module. When the function pointer is called from within the test framework a segmentation fault occurs. If I debug the program using 'gdb' I am able to directly call the function pointer and it works correctly.
I am using CppUTest as the unit test framework and have compiled my object files using gcc.
This function has worked in production code prior to altering it to use a function pointer for pthread_create, so I am confident in the function in general.
Stack Trace from GDB
> Starting program:
> /home/lucid/depot/torr_linux_common_dev/main/src/Utilities/tests/testRunner
> [Thread debugging using libthread_db enabled] Using host libthread_db
> library "/lib/i386-linux-gnu/libthread_db.so.1".
>
> Program received signal SIGSEGV, Segmentation fault. 0x080660c4 in
> sys_pthreads_create () (gdb) backtrace
> #0 0x080660c4 in sys_pthreads_create ()
> #1 0x08049ee4 in th_start_thread_name (thread=0x8049e64 <TestThread>, arg=0x0, opts=0x0, name=0x0) at thr.c:177
> #2 0x08049e47 in test_ThreadTestGroup_ThreadCreateUnnamed_wrapper_c () at thr_test.c:66
> #3 0x08049223 in TEST_ThreadTestGroup_ThreadCreateUnnamed_Test::testBody
> (this=0x806cc90) at testRunner.c:21
> #4 0x0805576a in PlatformSpecificSetJmpImplementation ()
> #5 0x08053ab7 in Utest::run() ()
> #6 0x080550d5 in UtestShell::runOneTestInCurrentProcess(TestPlugin*, TestResult&) ()
> #7 0x08053645 in helperDoRunOneTestInCurrentProcess ()
> #8 0x0805576a in PlatformSpecificSetJmpImplementation ()
> #9 0x08053b8f in UtestShell::runOneTest(TestPlugin*, TestResult&) ()
> #10 0x080530ef in TestRegistry::runAllTests(TestResult&) ()
> #11 0x0804a3ef in CommandLineTestRunner::runAllTests() ()
> #12 0x0804a4e9 in CommandLineTestRunner::runAllTestsMain() ()
> #13 0x0804a628 in CommandLineTestRunner::RunAllTests(int, char const**) ()
> #14 0x08049246 in main (argc=1, argv=0xbffff244) at testRunner.c:25
If I call the function pointer from within gdb it works
(gdb) p (*sys_pthreads_create)(&thr, 0, thread, arg)
[New Thread 0xb7c01b40 (LWP 17717)]
$4 = 0
Function I am testing
#include <pthread.h>
#include "mypthreads.h"
long th_start_thread_name(TH_THREAD_FUNC thread, void *arg, th_opts *opts, const char* name)
{
pthread_t thr;
int ret, sret;
//pthread_create(opts ? &opts->thr : &thr, NULL, thread, arg);
ret = (*sys_pthreads_create)(opts ? &opts->thr : &thr, 0, thread, arg);
if (ret == 0 && name != NULL)
{
extern int pthread_setname_np(pthread_t thr, const char *name); /* Fix warning from missing prototype. */
sret = pthread_setname_np(opts ? opts->thr : thr, name);
/* pthreads says that thread names must not exceed 16, including NULL. */
if (sret != 0 && strlen(name) > 15)
{
ret = -1;
}
}
return (long)ret;
}
mypthreads.h
extern int (*sys_pthreads_create(pthread_t *, const pthread_attr_t *,
void *(*) (void*), void *));
mypthreads.c
#include <stdio.h>
#include <pthread.h>
int my_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
printf("Did you get the messsage?");
return pthread_create(thread, attr, start_routine, arg);
}
int (*sys_pthreads_create)(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) = my_pthread_create;
Edit: Added output from gdb when I call the function pointer and it succeeds.
The problem is that your declaration in mypthreads.h has the wrong type:
extern int (*sys_pthreads_create(pthread_t *, const pthread_attr_t *, void *(*) (void*), void *));
Due to a misplaced parantheses, the type of this symbol is a function that returns a pointer to int, but your actual sys_pthreads_create object is a pointer to a function.
This means that when you call:
ret = (*sys_pthreads_create)(opts ? &opts->thr : &thr, 0, thread, arg);
sys_pthreads_create is converted to a pointer to a function by implicitly taking the address of it, then that address is dereferenced and called. But that's not really the address of a function - it's the address of a pointer to a function! So the call jumps into the data segment where sys_pthreads_create lives and crashes when it tries to execute the function pointer as code (or crashes due to a non-executable mapping).
There's a clue to this in the gdb output:
#0 0x080660c4 in sys_pthreads_create ()
It says that it's executing within sys_pthreads_create - but sys_pthreads_create is a variable, not a function.
The compiler would have diagnosed this for you if you had included <mypthreads.h> in mypthreads.c, because the conflicting types for sys_pthreads_create would have been visible to it (that's why you should always include the header file that declares objects in the source files that define those objects).
The correct declaration of course is the one that matches mypthreads.c:
extern int (*sys_pthreads_create)(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
The reason that gdb was able to call the function pointer successfully was that gdb uses the type information stored in the debugging info to determine the type of sys_pthreads_create, not the bogus information from the header file.

Interposing library functions via linker script: other functions cause segfault

I'm currently utilizing the LD_PRELOAD trick and am utilizing a linker version script as detailed in an article on another website. My MCVE code is included below.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE (1024)
int __printf__(const char *fmt, ...)
{
char buf[BUFFER_SIZE] = { 0 };
int ret;
int len;
va_list args;
va_start(args, fmt);
vsnprintf(buf, BUFFER_SIZE - 1, fmt, args);
#if 1
//typeof(vsnprintf) *real_func = dlsym(RTLD_NEXT, "vsnprintf");
//(*real_func)(buf, BUFFER_SIZE - 1, fmt, args);
#endif
len = strlen(buf);
ret = write(STDOUT_FILENO, buf, len);
va_end(args);
return ret;
}
asm(".symver __printf__, __printf_chk#GLIBC_2.3.4");
If I modify my custom printf function to simply write a static string, no problems. However, I want to modify the data being sent to the console via printf (add a prefix, suffix, and set certain character to UPPERCASE, etc). It seems that whenever I attempt to use any other printf-family functions to generate a copy of the user-provided string, I get a segfault, as shown below.
Program received signal SIGSEGV, Segmentation fault.
strchrnul () at ../sysdeps/x86_64/strchr.S:32
32 ../sysdeps/x86_64/strchr.S: No such file or directory.
(gdb) bt
#0 strchrnul () at ../sysdeps/x86_64/strchr.S:32
#1 0x00007ffff78591c8 in __find_specmb (format=0x1 <error: Cannot access memory at address 0x1>) at printf-parse.h:108
#2 _IO_vfprintf_internal (s=s#entry=0x7fffffffc380, format=format#entry=0x1 <error: Cannot access memory at address 0x1>, ap=ap#entry=0x7fffffffc4f8) at vfprintf.c:1312
#3 0x00007ffff7882989 in _IO_vsnprintf (string=0x7fffffffc510 "", maxlen=<optimized out>, format=0x1 <error: Cannot access memory at address 0x1>, args=0x7fffffffc4f8)
at vsnprintf.c:114
#4 0x00007ffff7bd58a1 in __printf__ (fmt=0x1 <error: Cannot access memory at address 0x1>) at libfakeprintf.c:19
#5 0x00000000004004aa in printf (__fmt=0x400644 "%s received %d args\n") at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
#6 main (argc=<optimized out>, argv=<optimized out>) at print_args.c:5
(gdb) quit
What is causing this crash?
Thank you.
You have overridden the glibc internal function __printf_chk , however this function does not have a prototype that matches printf. It's prototype is:
int __printf_chk(int flag, const char * format, ...);
So make sure your own __printf__ function has that prototype too.
There's a brief description of __printf_chk here

GDB breakpoint when executing external program through system()

I have the function system() call a separate script that has already been compiled. But I'd like to be able to set a breakpoint in functions within THAT specific file.
So:
File A:
system("./fileB");
File B:
void main() {
/* etc */
}
I'd like to be able to set a breakpoint at main after the system command is called.
Any help would be appreciated!
Newer versions of GDB (7.1+) can debug multiple programs at once and can indeed support this:
run-program.c
#include <stdlib.h>
int main()
{
system("./program-i-want-to-debug");
return 0;
}
program-i-want-to-debug.c
#include <stdio.h>
int main()
{
printf("Hello, World\n");
return 0;
}
run-program.gdb
set detach-on-fork off
set target-async on
set pagination off
set non-stop on
add-inferior -exec program-i-want-to-debug
break program-i-want-to-debug.c:5
file run-program
run
inferior 3
backtrace
Sample session
$ gdb -q -x run-program.gdb
Added inferior 2
Breakpoint 1 at 0x400441: file program-i-want-to-debug.c, line 5.
[New process 20297]
process 20297 is executing new program: /usr/bin/bash
process 20297 is executing new program: /home/scottt/Dropbox/stackoverflow/program-i-want-to-debug
Reading symbols from /home/scottt/Dropbox/stackoverflow/program-i-want-to-debug...done.
Breakpoint 1, main () at program-i-want-to-debug.c:5
5 printf("Hello, World\n");
[Switching to inferior 3 [process 20297] (/home/scottt/Dropbox/stackoverflow/program-i-want-to-debug)]
[Switching to thread 2 (process 20297)]
#0 main () at program-i-want-to-debug.c:5
5 printf("Hello, World\n");
#0 main () at program-i-want-to-debug.c:5
Obviously you'd want to compile the programs with debug info (gcc -g).
Maybe I do not catch your point. It seems that starting gdb debug on File A and setting a breakpoint on "FileB:line of main" resolve your problem.

pthread_cond_broadcast broken with dlsym?

I am trying to interpose calls to pthread_cond_broadcast using LD_PRELOAD mechanism. My interposed pthread_cond_broadcast function just calls the original pthread_cond_broadcast. However, for a very simple pthread code where both pthread_cond_wait and pthread_cond_broadcast get invoked, I either end up with a segfault in glibc (for glibc 2.11.1) or the program hangs (for glibc 2.15). Any clues on that is going on?
The interposition code (that gets compiled as a shared library):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>
static int (*orig_pthread_cond_broadcast)(pthread_cond_t *cond) = NULL;
__attribute__((constructor))
static void start() {
orig_pthread_cond_broadcast =
(int (*)()) dlsym(RTLD_NEXT, "pthread_cond_broadcast");
if (orig_pthread_cond_broadcast == NULL) {
printf("pthread_cond_broadcast not found!!!\n");
exit(1);
}
}
__attribute__((__visibility__("default")))
int pthread_cond_broadcast(pthread_cond_t *cond) {
return orig_pthread_cond_broadcast(cond);
}
The simple pthread program:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t cond_mutex;
pthread_cond_t cond_var;
int condition;
void *thread0_work(void *arg) {
pthread_mutex_lock(&cond_mutex);
printf("Signal\n");
condition = 1;
pthread_cond_broadcast(&cond_var);
pthread_mutex_unlock(&cond_mutex);
return NULL;
}
void *thread1_work(void *arg) {
pthread_mutex_lock(&cond_mutex);
while (condition == 0) {
printf("Wait\n");
pthread_cond_wait(&cond_var, &cond_mutex);
printf("Done waiting\n");
}
pthread_mutex_unlock(&cond_mutex);
return NULL;
}
int main() {
pthread_t thread1;
pthread_mutex_init(&cond_mutex, NULL);
pthread_cond_init(&cond_var, NULL);
pthread_create(&thread1, NULL, thread1_work, NULL);
// Slowdown this thread, so the thread 1 does pthread_cond_wait.
usleep(1000);
thread0_work(NULL);
pthread_join(thread1, NULL);
return 0;
}
EDIT:
For glibc 2.11.1, gdb bt gives:
(gdb) set environment LD_PRELOAD=./libintercept.so
(gdb) run
Starting program: /home/seguljac/intercept/main
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff7436700 (LWP 19165)]
Wait
Signal
Before pthread_cond_broadcast
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff79ca0e7 in pthread_cond_broadcast##GLIBC_2.3.2 () from /lib/libpthread.so.0
(gdb) bt
#0 0x00007ffff79ca0e7 in pthread_cond_broadcast##GLIBC_2.3.2 () from /lib/libpthread.so.0
#1 0x00007ffff7bdb769 in pthread_cond_broadcast () from ./libintercept.so
#2 0x00000000004008e8 in thread0_work ()
#3 0x00000000004009a4 in main ()
EDIT 2:
(Solved)
As suggested by R.. (thanks!), the issue is that on my platform pthread_cond_broadcast is a versioned symbol, and dlsym gives the wrong version. This blog explains this situation in great detail: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/
The call through your function seems to end up in a different version of the function:
With LD_PRELOAD: __pthread_cond_broadcast_2_0 (cond=0x804a060) at old_pthread_cond_broadcast.c:37
Without LD_PRELOAD: pthread_cond_broadcast##GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/pthread_cond_broadcast.S:39
So your situation is similar to this question, i.e. you are getting incompatible versions of pthread functions: symbol versioning and dlsym
This page gives one way to solve the problem, though a bit complex: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/

Resources