Assume that we have a single thread program and we hope to capture the value of program counter (PC) when a predefined interrupt occurs (like a timer interrupt).
It seems easy as you know we just write a specific assembly code using a special keyword __asm__ and pop the value on the top of the stack after making a shift 4 byte.
What about Multithreaded programs ?
How can we get values of all threads from another thread which run in the same process? (It seems extremely incredible to get values from thread which run on a separate core in multi-core processors).
(in multithreaded programs, every thread has its stack and registers too).
I want to implement a saboteur thread.
in order to perform fault injection in the target multi-threaded program, the model of fault is SEU (single error upset) which means that an arbitrary bit in the program counter register modified randomly (bit-flip) causing to violate the right program sequence. therefore, control flow error (CFE) occurs.
Since our target program is a multi-threaded program, we have to perform fault injection on all threads' PC. This is the task of saboteur tread. It should be able to obtain threads' PC to perform fault injection.
assume we have this code,
main ()
{
foo
}
void foo()
{
__asm__{
pop "%eax"
pop "%ebx" // now ebx holds porgram counter value (for main thread)
// her code injection like 00000111 XOR ebx for example
push ...
push ...
};
}
If our program was a multithreaded program.
is it means that we have more than one stack?
when OS perform context switching, it means that the stack and registers of the thread that was running moved to some place in the memory. Does this mean that if we want to get the values of the program counter for those threads, we find them in memory? where? and is it possible during run-time?
When you install a signal handler using sigaction() with SA_SIGINFO in the flags, the second parameter the signal handler gets is a pointer to siginfo_t, and the third parameter is a pointer to an ucontext_t. In Linux, this structure contains, among other things, the set of register values when the kernel interrupted the thread, including program counter.
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <signal.h>
#include <ucontext.h>
#if defined(__x86_64__)
#define PROGCOUNTER(ctx) (((ucontext *)ctx)->uc_mcontext.greg[REG_RIP])
#elif defined(__i386__)
#define PROGCOUNTER(ctx) (((ucontext *)ctx)->uc_mcontext.greg[REG_EIP])
#else
#error Unsupported architecture.
#endif
void signal_handler(int signum, siginfo_t *info, void *context)
{
const size_t program_counter = PROGCOUNTER(context);
/* Do something ... */
}
As usual, printf() et al. are not async-signal safe, which means it is not safe to use them in a signal handler. If you wish to output the program counter to e.g. standard error, you should not use any of the standard I/O to print to stderr, and instead construct the string to be printed by hand, and use a loop to write() the contents of the string; for example,
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
static void wrerr(const char *p)
{
const int saved_errno = errno;
const char *q = p;
ssize_t n;
/* Nothing to print? */
if (!p || !*p)
return;
/* Find end of q. strlen() is not async-signal safe. */
while (*q) q++;
/* Write data from p to q. */
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1 || errno != EINTR)
break;
}
errno = saved_errno;
}
Note that you'll want to keep the value of errno unchanged in the signal handler, so that if interrupted after a failed library function, the interrupted thread still sees the correct errno value. (It's mostly a debugging issue, and "good form"; some idiots pooh-pooh this as "it does not happen often enough for me to worry about".)
Your program can examine the /proc/self/maps pseudofile (it is not a real file, but something that the kernel generates on the fly when the file is read) to see the memory regions used by the program, to determine whether the program was running a C library function (very common) or something else when the interrupt was delivered.
If you wish to interrupt a specific thread in a multi-threaded program, just use pthread_kill(). Otherwise the signal is delivered to one of the threads that has not blocked the signal, more or less at random.
Here is an example program, that is tested to in x86-64 (AMD64) and x86, when compiled with GCC-4.8.4 using -Wall -O2:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <ucontext.h>
#include <time.h>
#include <stdio.h>
#if defined(__x86_64__)
#define PROGRAM_COUNTER(mctx) ((mctx).gregs[REG_RIP])
#define STACK_POINTER(mctx) ((mctx).gregs[REG_RSP])
#elif defined(__i386__)
#define PROGRAM_COUNTER(mctx) ((mctx).gregs[REG_EIP])
#define STACK_POINTER(mctx) ((mctx).gregs[REG_ESP])
#else
#error Unsupported hardware architecture.
#endif
#define MAX_SIGNALS 64
#define MCTX(ctx) (((ucontext_t *)ctx)->uc_mcontext)
static void wrerr(const char *p, const char *q)
{
while (p < q) {
ssize_t n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1 || errno != EINTR)
break;
}
}
static const char hexc[16] = "0123456789abcdef";
static inline char *prehex(char *before, size_t value)
{
do {
*(--before) = hexc[value & 15];
value /= (size_t)16;
} while (value);
*(--before) = 'x';
*(--before) = '0';
return before;
}
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = signum;
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
static size_t jump_target[MAX_SIGNALS] = { 0 };
static size_t jump_stack[MAX_SIGNALS] = { 0 };
static void handle_jump(int signum, siginfo_t *info, void *context)
{
const int saved_errno = errno;
char buffer[128];
char *p = buffer + sizeof buffer;
*(--p) = '\n';
p = prehex(p, STACK_POINTER(MCTX(context)));
*(--p) = ' ';
*(--p) = 'k';
*(--p) = 'c';
*(--p) = 'a';
*(--p) = 't';
*(--p) = 's';
*(--p) = ' ';
*(--p) = ',';
p = prehex(p, PROGRAM_COUNTER(MCTX(context)));
*(--p) = ' ';
*(--p) = '#';
wrerr(p, buffer + sizeof buffer);
if (signum >= 0 && signum < MAX_SIGNALS) {
if (jump_target[signum])
PROGRAM_COUNTER(MCTX(context)) = jump_target[signum];
if (jump_stack[signum])
STACK_POINTER(MCTX(context)) = jump_stack[signum];
}
errno = saved_errno;
}
static int install_jump(const int signum, void *target, size_t stack)
{
struct sigaction act;
if (signum < 0 || signum >= MAX_SIGNALS)
return errno = EINVAL;
jump_target[signum] = (size_t)target;
jump_stack[signum] = (size_t)stack;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_sigaction = handle_jump;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(int argc, char *argv[])
{
const struct timespec sec = { .tv_sec = 1, .tv_nsec = 0L };
const int pid = (int)getpid();
ucontext_t ctx;
printf("Run\n");
printf("\tkill -KILL %d\n", pid);
printf("\tkill -TERM %d\n", pid);
printf("\tkill -HUP %d\n", pid);
printf("\tkill -INT %d\n", pid);
printf("or press Ctrl+C to stop this process, or\n");
printf("\tkill -USR1 %d\n", pid);
printf("\tkill -USR2 %d\n", pid);
printf("to send the respective signal to this process.\n");
fflush(stdout);
if (install_done(SIGTERM) ||
install_done(SIGHUP) ||
install_done(SIGINT) ) {
printf("Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
getcontext(&ctx);
if (install_jump(SIGUSR1, &&usr1_target, STACK_POINTER(MCTX(&ctx))) ||
install_jump(SIGUSR2, &&usr2_target, STACK_POINTER(MCTX(&ctx))) ) {
printf("Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* These are expressions that should evaluate to false, but the compiler
* should not be able to optimize them away. */
if (argv[0][1] == 'A') {
usr1_target:
fputs("USR1\n", stdout);
fflush(stdout);
}
if (argv[0][1] == 'B') {
usr2_target:
fputs("USR2\n", stdout);
fflush(stdout);
}
while (!done) {
putchar('.');
fflush(stdout);
nanosleep(&sec, NULL);
}
fputs("\nAll done.\n", stdout);
fflush(stdout);
return EXIT_SUCCESS;
}
If you save the above as example.c, you can compile it using
gcc -Wall -O2 example.c -o example
and run it
./example
Press Ctrl+C to exit the program. Copy the commands (for sending SIGUSR1 and SIGUSR2 signals), and run them from another window, and you'll see they modify the position for current execution. (The signals cause the program counter/instruction pointer to jump back, into an if clause that should never be executed otherwise.)
There are two sets of signal handlers. handle_done() just sets the done flag. handle_jump() outputs a message to standard error (using low-level I/O), and if specified, updates the program counter (instruction pointer) and stack pointer.
The stack pointer is the tricky part when creating an example program like this. It would be easy if we were satisfied with just crashing the program. However, an example is only useful if it works.
When we arbitrarily change the program counter/instruction pointer, and the interrupt was delivered when in a function call (most C library functions...), the return address is left on the stack. The kernel can deliver the interrupt at any point, so we cannot even assume that the interrupt was delivered when in a function call, either! So, to make sure the test program does not crash, I had to update the program counter/instruction pointer and stack pointer as a pair.
When a jump signal is received, the stack pointer is reset to a value I obtained using getcontext(). This is not guaranteed to be suitable for any jump location; it's just the best I could do for a minimal example. I definitely assume the jump labels are nearby, and not in subscopes where the compiler is likely to mess with the stack, mind you.
It is also important to keep in mind that because we are dealing with details left to the C compiler, we must conform to whatever binary code the compiler produces, not the other way around. For reliable manipulation of a process and its threads, ptrace() is a much better (and honestly, easier) interface. You just set up a parent process, and in the target traced child process, explicitly allow the tracing. I've shown examples here and here (both answers to the same question) on how to start, stop, and single-step individual threads in a target process. The hardest part is understanding the overall scheme, the concepts; the code itself is easier -- and much, much more robust than this signal-handler-context-manipulation way.
For self-introducing register errors (either to program counter/instruction pointer, or to any other register), with the assumption that most of the time that leads to the process crashing, this signal handler context manipulation should be sufficient.
No, it's not possible while a thread is executing. While a thread is executing, the current value of its program counter (EIP) is private to the CPU core it's running on. It's not available in memory anywhere.
It would be possible for an architecture to have special instructions to send inter-processor requests with queries about execution state, but x86 doesn't have this.
However, you can use ptrace system calls to do anything a debugger could; interrupt another thread and modify any of its state (general purpose registers, flags, program counter, etc. etc.) I can't give you an example, I just know that's the system call that debuggers use to modify the saved state of another thread / process. For example, this question asks about modifying another process's RIP using ptrace (for testing code-injection).
I'm not sure it's viable to ptrace one thread from another thread in the same process; your fault injector might work better as a separate process that interferes with the threads of another process.
Anyway, what will happen when you make a ptrace system call to modify something in another thread is that the CPU running your system call will send and inter-processor message to the kernel on the CPU running the other thread, which will interrupt that thread you want to mess with. Its state will be saved into memory by the kernel, where it can be modified by any CPU.
Once the other thread stops running, it isn't strongly associated with any CPU anymore. It will be cheaper to resume it on the CPU that already has hot caches for it, but that isn't guaranteed because that CPU could have started running any other thread once it was no longer busy running the thread you caused to be stopped.
Side note, not relevant to inter-thread fault injection:
Your C function for modifying EIP (foo()) is really ugly, BTW:
First of all, it's MSVC inline asm, so no Linux compiler will accept it (maybe icc?). Second, it only works with -fno-omit-frame-pointer, because it assumes that its inside a function that's pushed %ebp.
It would be so much easier to just write the whole function in asm. In 64bit non-inline asm, you'd just write:
global fault_inject_program_counter
fault_inject_program_counter:
xor qword [rsp], 0b00000111
ret
and assemble that file separately with NASM or YASM, and link the .o with code that calls it. (I'm assuming you'd prefer Intel syntax, since you used MSVC-style asm {} instead GNU C asm("pop ; ... ; "::: ); inline asm.)
an inline asm version might look like:
// this can't possibly work if inlined, or if compiled without `-fno-omit-frame-pointer
__attribute__((noinline)) void foo()
{
__asm__ volatile(
// "pop %eax\n\t"
// "pop %ebx\n\t" // now ebx holds the return address
// here code injection like 00000111 XOR ebx for example
// normal people would just write
"xorl $0b00000111, -4(%esp)\n\t"
// to modify the return value in-place, in a function with a frame pointer.
// push ...
// push ...
);
}
Related
I have a simple program using signal with the user's handlers.
#include <signal.h>
#include <stdio.h>
#include <zconf.h>
int x = 0;
int i = 3;
void catcher3(int signum) {
i = 1;
}
void catcher2(int signum) {
// Stuck in infinity loop here.
// Happens even with i == 0
if (i != 0) {
x = 5;
}
}
void catcher1(int signum) {
printf("i = %d\n", i);
i--;
if (i == 0) {
signal(SIGFPE, catcher2);
signal(SIGTERM, catcher3);
}
}
int main() {
signal(SIGFPE, catcher1);
x = 10 / x;
printf("Goodbye");
}
While I expect it to print:
3
2
1
Goodbye
It actually prints:
3
2
1
# Infinity loop within catcher2
My questions are:
On running a user handler like catcher1, to which point the code returns after the handler's execution? I would expect it continue the execution but it re-runs the signal handler.
What causes the infinity loop?
How to fix it?
Why sending SIGTERM won't print "Goodbye"? (kill -s TERM <pid>)
As pointed out by AProgrammer, the program doesn't necessarily read x after returning from the handler, even if x is marked volatile (which it should be anyway). This is because the execution continues to the offending instruction. The read from memory and the actual division could be separate instructions.
To get around this you will have to continue the execution to a point before x was read from memory.
You can modify your program as follows -
#include <csetjmp>
jmp_buf fpe;
volatile int x = 0; // Notice the volatile
volatile int i = 3;
void catcher2(int signum) {
if (i != 0) {
x = 5;
longjump(fpe, 1);
}
}
int main() {
signal(SIGFPE, catcher1);
setjump(fpe);
x = 10 / x;
printf("Goodbye");
}
Rest of the functions can remain the same.
You should also not be using printf from the signal handler. Instead use write directly to print debug messages as -
write(1, "SIGNAL\n", sizeof("SIGNAL\n"));
The handling of signals is complex and full of implementation defined, unspecified and undefined behavior. If you want to be portable, there is in fact very few things that you can do. Mostly reading and writing volatile sig_atomic_t and calling _Exit. Depending on the signal number, it is often undefined if you leave the signal handler in another way than calling _Exit.
In your case, I think FPE is one of those signals for which leaving normally the signal handler is UB. The best I can see is restarting the machine instruction which triggered the signal. Few architectures, and last I looked x86 was not one of them, provide a way to do 10/x without loading x in a register; that means that restarting the instruction will always restart the signal, even if you modify x and x us a volatile sig_atomtic_t.
Usually longjmp is also able to leave signal handler. #Bodo confirmed that using setjmp and longjmp to restart the division, you can get the behavior you want.
Note: on Unix there is another set of functions, sigaction, siglongjump and others, which is better to use. In fact I don't recommend using something else in any serious program.
Tried my best to figure this out on my own, but I really do not want to continue tampering with things that I do not fully understand. So for a programming assignment I have to do in C, I need to terminate a program upon the user entering CTRL+D key stroke via a terminal. I tried to isolate that functionality in a smaller test function, but now my CTRL+D behaves as my CTRL+C and CTRL+C does not have any effect, even outside of the program when it finishes executing. This is the program that caused this change:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
printf("\n");
signal(SIGINT, SIG_DFL);
exit(0);
}
int main(){
signal(SIGINT, ctrlD);
while(1) {
printf("Hello\n");
sleep(5);
}
}
The line signal(SIGINT, SIG_DFL); was added afterward upon realizing my CTRL+C no longer worked. I thought it would return the keystrokes to their original functionalities, but to no avail. What do I do to get back the original functionalities while also making this program work with CTRL+D?
***EDIT: This question seems to have gone off the rails a bit. I get now that Ctrl+D is not a signal. Nonetheless, I no longer have the functionality of Ctrl+C anymore when attempting to use it in my MAC OS terminal, and instead Ctrl+D seems to have that exact functionality. HOW exactly can I return each to have the functionality that they had before I went on this haphazard journey?
If your intention is to restore signal's default behavior after executing handler then, pass SA_RESETHAND flag to sa_flags while registering signal action. For example.
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESETHAND;
act.sa_handler = some_handler;
sigaction(SIGINT, &act, NULL);
From sigaction() man
SA_RESETHAND
Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when
establishing a signal handler.
If you write a program to explore signals, it is much better to write it carefully, using proper POSIX interfaces (sigaction() instead of signal()), and avoiding undefined behaviour (using non-async-signal safe functions in a signal handler).
Consider, for example, the following program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
static volatile sig_atomic_t sigint_count = 0;
static void catch_sigint(int signum)
{
if (signum == SIGINT)
sigint_count++;
}
static int install_sigint(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = catch_sigint;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) == -1)
return errno;
return 0;
}
static int install_default(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
struct timespec duration;
int result;
if (install_sigint()) {
fprintf(stderr, "Cannot install SIGINT handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
duration.tv_sec = 5;
duration.tv_nsec = 0; /* 1/1000000000ths of a second. Nine zeroes. */
printf("Sleeping for %d seconds.\n", (int)duration.tv_sec);
fflush(stdout);
while (1) {
result = nanosleep(&duration, &duration);
if (!result)
break;
if (errno != EINTR) {
fprintf(stderr, "nanosleep() failed: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* nanosleep was interrupted by a delivery of a signal. */
if (sigint_count >= 3) {
/* Ctrl+C pressed three or more times. */
if (install_default(SIGINT) == -1) {
fprintf(stderr, "Cannot revert SIGINT to the default handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("SIGINT has been reverted to the default handler.\n");
fflush(stderr);
}
}
if (sigint_count > 0)
printf("You pressed Ctrl+C %d time%s.\n", (int)sigint_count, (sigint_count > 1) ? "s" : "");
else
printf("You did not press Ctrl+C at all.\n");
return EXIT_SUCCESS;
}
The #define tells your C library (glibc in particular) that you want POSIX.1-2008 (and later) features from it.
The INT signal handler only increments a volatile sig_atomic_t counter. Note that this type may have a very small range it can represent; 0 to 127, inclusive, should be safe.
The main program waits using the POSIX nanosleep() function. On some systems, sleep() may be implemented via the SIGALRM function, so it is better avoided when using signals otherwise; nanosleep() does not interfere with signals like that at all. Plus, nanosleep() can return the amount of time remaining, if it is interrupted by a signal delivery.
In the main loop, nanosleep() will return 0, if it has slept the entire interval (but note that it may not update the remaining time to 0 in this case). If it is interrupted by the delivery of a signal, it will return -1 with errno == EINTR, and the remaining time updated. (The first pointer is to the duration of the sleep, and the second is to where the remaining time should be stored. You can use the same structure for both.)
Normally, the main loop does only one iteration. It can do more than one iteration, if it is interrupted by the delivery of a signal.
When the main loop detects that sigint_count is at least three, i.e. it has received at least three INT signals, it resets the signal handler back to default.
(Note that both the memset() and the sigemptyset() are important when clearing the struct sigaction structure. The memset() ensures that future code is backwards compatible with older code, by ensuring even padding fields are cleared. And sigemptyset() is the safe way to clear the signal mask (set of signals blocked while the handler runs).)
(In theory, memset() is not async-signal-safe, while both sigemptyset() and sigaction() are. This is why I reset the signal handler in the main program, and not in the signal handler.)
If you want to print from a signal handler, you need to use low-level I/O, because <stdio.h> functions are not async-signal safe. For example, you can use the following function to print strings to standard output:
static int wrerr(const char *p)
{
const int saved_errno = errno;
int retval = 0;
if (p) {
const char *q = p;
ssize_t n;
while (*q)
q++;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
}
errno = saved_errno;
return retval;
}
The above wrerr() function is async-signal safe (because it only uses async-signal safe functions itself), and it even keeps errno unchanged. (Many guides forget to mention that it is quite important for a signal handler to keep errno unchanged. Otherwise, when a function is interrupted by a signal handler, and that signal handler modifies errno, the original function will return -1 to indicate an error, but then errno is no longer EINTR!)
You can just use wrerr("INT signal!\n") if you want. The return value from wrerr() is zero if the write was successful, and an errno error code otherwise. It ignores interrupts itself.
Do note that you should not mix stderr output via fprintf() or other <stdio.h> functions with the above (except perhaps for printing error messages when the program aborts). Mixing them is not undefined behaviour, it just may yield surprising results, like wrerr() output appearing in the midst of a fprintf(stderr,...) output.
Its because of exit(0) statement in the handler, when SIGINT is raised, handler strlD gets called and you might thinking why signal(SIGINT,SIG_DFL) didn't work ? Actually it works. But your main process a.out get terminated successfully there itself by calling exit(0). remove exit(0) if you want to restore the behavior of SIGINT.
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
//printf("CTRL+C pressed\n");/* just to observe I added one printf
statement, Ideally there shouldn't be any printf here */
signal(SIGINT, SIG_DFL);/*restoring back to original action */
}
int main(){
signal(SIGINT, ctrlD);/*1st time when CTRL+C pressed, handler ctrlD gets called */
while(1) {
printf("Hello\n");
sleep(5);
}
return 0;
}
Also its advisable to use sigaction() instead of signal() as told here What is the difference between sigaction and signal? . Read man 2 sigaction and man 2 exit to check what exit(0) means.
Also this How to avoid using printf in a signal handler?
Edit :
void ctrlD(int sig){
/* printf("CTRL+C pressed \n"); */
signal(SIGINT, SIG_DFL); /* only one time CTRL+C works
after that SIG_DFL will terminate whole process */
}
int main(){
signal(SIGINT, ctrlD); /* if you press CTRL+C then it will go to handler
and terminate */
int ch;
while( ((ch = getchar())!=EOF) ) { /* wait or read char until CTrl+D is not pressed */
printf("Hello : %d \n",ch);/* ASCII equivalent of char */
}
return 0;
}
Thank you everyone who contributed to this question. The resources provided/linked were tremendously helpful in learning more about signals (and that EOF isn't a signal), among the other wealth of information provided.
After some more research, I found out that somehow, either through some accidental bash command gone awry, or perhaps the program posted in my original question itself, I had altered the key mappings for my terminal's stty settings. If anyone finds themselves in this oddly specific situation in the future, I hope this can be of help, as it is what fixed my problem:
Enter the command $ stty -a to see all of your terminals settings, specifically the "cchars" section.
I then saw the reversal, and fixed it like so:
$ stty intr ^C
$ stty eof ^D
Then you can run $ stty -a once again to see that the changes have properly taken effect. Once again, thanks everyone.
I'm porting a software from an embedded computer to a Linux machine. (Ubuntu 14.04 or Raspbian (raspberry pi))
The original program was using setjmp/longjmp to handle timeout and CTRL+C event. It was running on a Microcontroller with a single main (one thread).
I'm trying to have a similar behaviour while using threads (pthreads).
The idea is that I want either a timeout or a CTRL+C to restart an infinite loop.
The original code was doing something like the code below. I don't mind to drop the setjmp/longjmp by something else. (ex: try/catch or signal or pthread_kill, conditional variable, etc..)
Any idea how to implement similar behavior with C/C++ ?
Here is the code which seems to partially work and is probably not recommended/broken:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <setjmp.h>
// Define
#define TICK_NS_TIME (10000000) // 0.01 sec = 10 ms (100 times per second)
#define NS_PER_SEC (1000000000) // Nano sec per second.
#define TICK_PER_SEC (NS_PER_SEC/TICK_NS_TIME) // Number of tick per second (Ex:100)
#define TIMEOUT_COUNT (30*TICK_PER_SEC) // 30 seconds timeout (with 100 tick per second)
// Env set/long jmp
#define ENV_SZ (2)
#define ENV_TIMEOUT (0)
#define ENV_CTRLC (1)
static jmp_buf env[ENV_SZ];
// Variables
int timeout_val;
// sig handler.
void signal_handler(int signo)
{
pthread_t self = pthread_self();
printf("Thread %lu in signal handler\n", (long)self);
if (signo == SIGINT) {
longjmp(env[ENV_CTRLC], 1); // Q?: Is it in the same thread ? (Never, Always, Sometimes?)
}
else
{
printf("Other signal received..quitting."); // Ex: kill -9 pid
exit(0);
}
}
// thread timer function
void* timer_function(void* in_param)
{
// Loop approx 100x per second.
for (;;) {
nanosleep((const struct timespec[]){{0, TICK_NS_TIME }}, NULL); // Sleep 10 ms seconds.
if (timeout_val) {
if (!--timeout_val) {
longjmp(env[ENV_TIMEOUT], 1); // longjmp when timer reaches 0. (Q?: Is this valid with multithread?)
}
}
}
}
// main
int main(int argc, char **argv)
{
int i;
int val;
struct sigaction actions;
pthread_t thread;
setvbuf (stdout, NULL, _IONBF, 0); // Make sure stdout is not buffered (ex:printf, etc.)
printf("[Program started]\r\n");
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = signal_handler;
val = sigaction(SIGINT, &actions, NULL);
pthread_create(&thread, NULL, timer_function, NULL); // timer thread for example
printf("[Timer thread started]\r\n");
// setting env.
val = setjmp(env[ENV_TIMEOUT]);
if (val!=0){ printf("[JMP TIMEOUT]\r\n"); }
val = setjmp(env[ENV_CTRLC]);
if (val!=0){ printf("[JMP CTRLC]\r\n"); }
// main loop
timeout_val = TIMEOUT_COUNT;
i = 0;
for (;;)
{
i++;
if (i > 10){ i = 0; printf("[%d]", timeout_val/TICK_PER_SEC); } // Number of seconds before time out.
sleep(1);
printf(".");
}
printf("Main completed\n");
return 0;
}
//Compile: g++ -pthread main.cpp -o main
Suggestion for alternative implementation would be great since I'm new to programming with threads !
setjmp() saves the information required to restore the calling environment. longjmp() can then restore this environment, but only within the same thread.
The C11 standard is explicit about the constraint of having the same thread:
7.13.2.1/2 If there has been no such invocation (i.e: of a previous setjmp), or if the invocation was from another thread of
execution, or if the function containing the invocation of the
setjmp macro has terminated execution in the interim, or if the
invocation of the setjmp macro was within the scope of an identifier
with variably modified type and execution has left that scope in the
interim, the behavior is undefined.
In fact, setjmp/longjmp are generally implemented by saving the stack pointer so that restoring it makes sense only int the same execution context.
Alternative
Unless I've missed something, you use the second thread only to act as a timer. You could instead get rid of your POSIX pthread, and use a timer signal activated with POSIX timer_create().
But be aware that using setjmp/longjmp from a signal handler (so already in your original code for CTRL+C) is tricky, as explained in this SO answer. So you'd consider sigsetjmp/siglongjmp.
For the records: C or C++ ?
Your question is tagged C. But you mention c++ try and catch. So for the sake of completeness:
in C++ setjmp should be replaced by a try/catch and the longjmp by throwing an exception. setjmp/longjmp are supported in C++ only if unwinding the stack wouldn't require invocation of any non-trivial destructor (see C++ standard, 18.10/4).
the exceptions are not propagated across the threads, unless catched and explicitely rethrown using std::rethrow_exception(). It's delicate, so refer to this SO question for for additional details. But it's possible and could solve your issue.
I have a large C/C++ program on a Suse linux system. We do automated testing of it with a bash script, which sends input to the program, and reads the output. It's mainly "black-box" testing, but some tests need to know a few internal details to determine if a test has passed.
One test in particular needs to know how times the program runs a certain function (which parses a particular response message). When that function runs it issues a log and increments a counter variable. The automated test currently determines the number of invocations by grepping in the log file for the log message, and counting the number of occurrences before and after the test. This isn't ideal, because the logs (syslog-ng) aren't guaranteed, and they're frequently turned off by configuration, because they're basically debug logs.
I'm looking for a better alternative. I can change the program to enhance the testability, but it shouldn't be heavy impact to normal operation. My first thought was, I could just read the counter after each test. Something like this:
gdb --pid=$PID --batch -ex "p numServerResponseX"
That's slow when it runs, but it's good because the program doesn't need to be changed at all. With a little work, I could probably write a ptrace command to do this a little more efficiently.
But I'm wondering if there isn't a simpler way to do this. Could I write the counter to shared memory (with shm_open / mmap), and then read /dev/shm in the bash script? Is there some simpler way I could setup the counter to make it easy to read, without making it slow to increment?
Edit:
Details: The test setup is like this:
testScript <-> sipp <-> programUnderTest <-> externalServer
The bash testScript injects sip messages with sipp, and it generally determines success or failure based on the completion code from sipp. But in certain tests it needs to know the number of responses the program received from the external server. The function "processServerResponseX" processes certain responses from the external server. During the testing there isn't much traffic running, so the function is only invoked perhaps 20 times over 10 seconds. When each test ends and we want to check the counter, there should be essentially no traffic. However during normal operation, it might be invoked hundreds of times a second. The function is roughly:
unsigned long int numServerResponseX;
int processServerResponseX(DMsg_t * dMsg, AppId id)
{
if (DEBUG_ENABLED)
{
syslog(priority, "%s received %d", __func__, (int) id);
}
myMutex->getLock();
numServerResponseX++;
doLockedStuff(dMsg, id);
myMutex->releaseLock();
return doOtherStuff(dMsg, id);
}
The script currently does:
grep processServerResponseX /var/log/logfile | wc -l
and compares the value before and after. My goal is to have this work even if DEBUG_ENABLED is false, and not have it be too slow. The program is multi-threaded, and it runs on an i86_64 smp machine, so adding any long blocking function would not be a good solution.
I would have that certain function "(which parses a particular response message)" write (probably using fopen then fprintf then fclose) some textual data somewhere.
That destination could be a FIFO (see fifo(7) ...) or a temporary file in a tmpfs file system (which is a RAM file system), maybe /run/
If your C++ program is big and complex enough, you could consider adding some probing facilities (some means for an external program to query about the internal state of your C++ program) e.g. a dedicated web service (using libonion in a separate thread), or some interface to systemd, or to D-bus, or some remote procedure call service like ONC/RPC, JSON-RPC, etc etc...
You might be interested by POCOlib. Perhaps its logging framework should interest you.
As you mentioned, you might use Posix shared memory & semaphores (see shm_overview(7) and sem_overview(7) ...).
Perhaps the Linux specific eventfd(2) is what you need.... (you could code a tiny C program to be invoked by your testing bash scripts....)
You could also try to change the command line (I forgot how to do that, maybe libproc or write to /proc/self/cmdline see proc(5)...). Then ps would show it.
I personally do usually use the methods Basile Starynkevitch outlined for this, but I wanted to bring up an alternative method using realtime signals.
I am not claiming this is the best solution, but it is simple to implement and has very little overhead. The main downside is that the size of the request and response are both limited to one int (or technically, anything representable by an int or by a void *).
Basically, you use a simple helper program to send a signal to the application. The signal has a payload of one int your application can examine, and based on it, the application responds by sending the same signal back to the originator, with an int of its own as payload.
If you don't need any locking, you can use a simple realtime signal handler. When it catches a signal, it examines the siginfo_t structure. If sent via sigqueue(), the request is in the si_value member of the siginfo_t structure. The handler answers to the originating process (si_pid member of the structure) using sigqueue(), with the response. This only requires about sixty lines of code to be added to your application. Here is an example application, app1.c:
#define _POSIX_C_SOURCE 200112L
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#define INFO_SIGNAL (SIGRTMAX-1)
/* This is the counter we're interested in */
static int counter = 0;
static void responder(int signum, siginfo_t *info,
void *context __attribute__((unused)))
{
if (info && info->si_code == SI_QUEUE) {
union sigval value;
int response, saved_errno;
/* We need to save errno, to avoid interfering with
* the interrupted thread. */
saved_errno = errno;
/* Incoming signal value (int) determines
* what we respond back with. */
switch (info->si_value.sival_int) {
case 0: /* Request loop counter */
response = *(volatile int *)&counter;
break;
/* Other codes? */
default: /* Respond with -1. */
response = -1;
}
/* Respond back to signaler. */
value.sival_ptr = (void *)0L;
value.sival_int = response;
sigqueue(info->si_pid, signum, value);
/* Restore errno. This way the interrupted thread
* will not notice any change in errno. */
errno = saved_errno;
}
}
static int install_responder(const int signum)
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = responder;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL))
return errno;
else
return 0;
}
int main(void)
{
if (install_responder(INFO_SIGNAL)) {
fprintf(stderr, "Cannot install responder signal handler: %s.\n",
strerror(errno));
return 1;
}
fprintf(stderr, "PID = %d\n", (int)getpid());
fflush(stderr);
/* The application follows.
* This one just loops at 100 Hz, printing a dot
* about once per second or so. */
while (1) {
struct timespec t;
counter++;
if (!(counter % 100)) {
putchar('.');
fflush(stdout);
}
t.tv_sec = 0;
t.tv_nsec = 10000000; /* 10ms */
nanosleep(&t, NULL);
/* Note: Since we ignore the remainder
* from the nanosleep call, we
* may sleep much shorter periods
* when a signal is delivered. */
}
return 0;
}
The above responder responds to query 0 with the counter value, and with -1 to everything else. You can add other queries simply by adding a suitable case statement in responder().
Note that locking primitives (except for sem_post()) are not async-signal safe, and thus should not be used in a signal handler. So, the above code cannot implement any locking.
Signal delivery can interrupt a thread in a blocking call. In the above application, the nanosleep() call is usually interrupted by the signal delivery, causing the sleep to be cut short. (Similarly, read() and write() calls may return -1 with errno == EINTR, if they were interrupted by signal delivery.)
If that is a problem, or you are not sure if all your code handles errno == EINTR correctly, or your counters need locking, you can use separate thread dedicated for the signal handling instead.
The dedicated thread will sleep unless a signal is delivered, and only requires a very small stack, so it really does not consume any significant resources at run time.
The target signal is blocked in all threads, with the dedicated thread waiting in sigwaitinfo(). If it catches any signals, it processes them just like above -- except that since this is a thread and not a signal handler per se, you can freely use any locking etc., and do not need to limit yourself to async-signal safe functions.
This threaded approach is slightly longer, adding almost a hundred lines of code to your application. (The differences are contained in the responder() and install_responder() functions; even the code added to main() is exactly the same as in app1.c.)
Here is app2.c:
#define _POSIX_C_SOURCE 200112L
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#define INFO_SIGNAL (SIGRTMAX-1)
/* This is the counter we're interested in */
static int counter = 0;
static void *responder(void *payload)
{
const int signum = (long)payload;
union sigval response;
sigset_t sigset;
siginfo_t info;
int result;
/* We wait on only one signal. */
sigemptyset(&sigset);
if (sigaddset(&sigset, signum))
return NULL;
/* Wait forever. This thread is automatically killed, when the
* main thread exits. */
while (1) {
result = sigwaitinfo(&sigset, &info);
if (result != signum) {
if (result != -1 || errno != EINTR)
return NULL;
/* A signal was delivered using *this* thread. */
continue;
}
/* We only respond to sigqueue()'d signals. */
if (info.si_code != SI_QUEUE)
continue;
/* Clear response. We don't leak stack data! */
memset(&response, 0, sizeof response);
/* Question? */
switch (info.si_value.sival_int) {
case 0: /* Counter */
response.sival_int = *(volatile int *)(&counter);
break;
default: /* Unknown; respond with -1. */
response.sival_int = -1;
}
/* Respond. */
sigqueue(info.si_pid, signum, response);
}
}
static int install_responder(const int signum)
{
pthread_t worker_id;
pthread_attr_t attrs;
sigset_t mask;
int retval;
/* Mask contains only signum. */
sigemptyset(&mask);
if (sigaddset(&mask, signum))
return errno;
/* Block signum, in all threads. */
if (sigprocmask(SIG_BLOCK, &mask, NULL))
return errno;
/* Start responder() thread with a small stack. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 32768);
retval = pthread_create(&worker_id, &attrs, responder,
(void *)(long)signum);
pthread_attr_destroy(&attrs);
return errno = retval;
}
int main(void)
{
if (install_responder(INFO_SIGNAL)) {
fprintf(stderr, "Cannot install responder signal handler: %s.\n",
strerror(errno));
return 1;
}
fprintf(stderr, "PID = %d\n", (int)getpid());
fflush(stderr);
while (1) {
struct timespec t;
counter++;
if (!(counter % 100)) {
putchar('.');
fflush(stdout);
}
t.tv_sec = 0;
t.tv_nsec = 10000000; /* 10ms */
nanosleep(&t, NULL);
}
return 0;
}
For both app1.c and app2.c the application itself is the same.
The only modifications needed to the application are making sure all the necessary header files get #included, adding responder() and install_responder(), and a call to install_responder() as early as possible in main().
(app1.c and app2.c only differ in responder() and install_responder(); and in that app2.c needs pthreads.)
Both app1.c and app2.c use the signal SIGRTMAX-1, which should be unused in most applications.
app2.c approach, also has a useful side-effect you might wish to use in general: if you use other signals in your application, but don't want them to interrupt blocking I/O calls et cetera -- perhaps you have a library that was written by a third party, and does not handle EINTR correctly, but you do need to use signals in your application --, you can simply block the signals after the install_responder() call in your application. The only thread, then, where the signals are not blocked is the responder thread, and the kernel will use tat to deliver the signals. Therefore, the only thread that will ever get interrupted by the signal delivery is the responder thread, more specifically sigwaitinfo() in responder(), and it ignores any interruptions. If you use for example async I/O or timers, or this is a heavy math or data processing application, this might be useful.
Both application implementations can be queried using a very simple query program, query.c:
#define _POSIX_C_SOURCE 200112L
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
int query(const pid_t process, const int signum,
const int question, int *const response)
{
sigset_t prevmask, waitset;
struct timespec timeout;
union sigval value;
siginfo_t info;
int result;
/* Value sent to the target process. */
value.sival_int = question;
/* Waitset contains only signum. */
sigemptyset(&waitset);
if (sigaddset(&waitset, signum))
return errno = EINVAL;
/* Block signum; save old mask into prevmask. */
if (sigprocmask(SIG_BLOCK, &waitset, &prevmask))
return errno;
/* Send the signal. */
if (sigqueue(process, signum, value)) {
const int saved_errno = errno;
sigprocmask(signum, &prevmask, NULL);
return errno = saved_errno;
}
while (1) {
/* Wait for a response within five seconds. */
timeout.tv_sec = 5;
timeout.tv_nsec = 0L;
/* Set si_code to an uninteresting value,
* just to be safe. */
info.si_code = SI_KERNEL;
result = sigtimedwait(&waitset, &info, &timeout);
if (result == -1) {
/* Some other signal delivered? */
if (errno == EINTR)
continue;
/* No response; fail. */
sigprocmask(SIG_SETMASK, &prevmask, NULL);
return errno = ETIMEDOUT;
}
/* Was this an interesting signal? */
if (result == signum && info.si_code == SI_QUEUE) {
if (response)
*response = info.si_value.sival_int;
/* Return success. */
sigprocmask(SIG_SETMASK, &prevmask, NULL);
return errno = 0;
}
}
}
int main(int argc, char *argv[])
{
pid_t pid;
int signum, question, response;
long value;
char dummy;
if (argc < 3 || argc > 4 ||
!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s PID SIGNAL [ QUERY ]\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (sscanf(argv[1], " %ld %c", &value, &dummy) != 1) {
fprintf(stderr, "%s: Invalid process ID.\n", argv[1]);
return 1;
}
pid = (pid_t)value;
if (pid < (pid_t)1 || value != (long)pid) {
fprintf(stderr, "%s: Invalid process ID.\n", argv[1]);
return 1;
}
if (sscanf(argv[2], "SIGRTMIN %ld %c", &value, &dummy) == 1)
signum = SIGRTMIN + (int)value;
else
if (sscanf(argv[2], "SIGRTMAX %ld %c", &value, &dummy) == 1)
signum = SIGRTMAX + (int)value;
else
if (sscanf(argv[2], " %ld %c", &value, &dummy) == 1)
signum = value;
else {
fprintf(stderr, "%s: Unknown signal.\n", argv[2]);
return 1;
}
if (signum < SIGRTMIN || signum > SIGRTMAX) {
fprintf(stderr, "%s: Not a realtime signal.\n", argv[2]);
return 1;
}
/* Clear the query union. */
if (argc > 3) {
if (sscanf(argv[3], " %d %c", &question, &dummy) != 1) {
fprintf(stderr, "%s: Invalid query.\n", argv[3]);
return 1;
}
} else
question = 0;
if (query(pid, signum, question, &response)) {
switch (errno) {
case EINVAL:
fprintf(stderr, "%s: Invalid signal.\n", argv[2]);
return 1;
case EPERM:
fprintf(stderr, "Signaling that process was not permitted.\n");
return 1;
case ESRCH:
fprintf(stderr, "No such process.\n");
return 1;
case ETIMEDOUT:
fprintf(stderr, "No response.\n");
return 1;
default:
fprintf(stderr, "Failed: %s.\n", strerror(errno));
return 1;
}
}
printf("%d\n", response);
return 0;
}
Note that I did not hardcode the signal number here; use SIGRTMAX-1 on the command line for app1.c and app2.c. (You can change it. query.c does understand SIGRTMIN+n too. You must use a realtime signal, SIGRTMIN+0 to SIGRTMAX-0, inclusive.)
You can compile all three programs using
gcc -Wall -O3 app1.c -o app1
gcc -Wall -O3 app2.c -lpthread -o app2
gcc -Wall -O3 query.c -o query
Both ./app1 and ./app2 print their PIDs, so you don't need to look for it. (You can find the PID using e.g. ps -o pid= -C app1 or ps -o pid= -C app2, though.)
If you run ./app1 or ./app2 in one shell (or both in separate shells), you can see them outputting the dots at about once per second. The counter increases every 1/100th of a second. (Press Ctrl+C to stop.)
If you run ./query PID SIGRTMAX-1 in another shell in the same directory on the same machine, you can see the counter value.
An example run on my machine:
A$ ./app1
PID = 28519
...........
B$ ./query 28519 SIGRTMAX-1
11387
C$ ./app2
PID = 28522
...
B$ ./query 28522 SIGRTMAX -1
371
As mentioned, the downside of this mechanism is that the response is limited to one int (or technically an int or a void *). There are ways around that, however, by also using some of the methods Basile Starynkevich outlined. Typically, the signal is then just a notification for the application that it should update the state stored in a file, shared memory segment, or wherever. I recommend using the dedicated thread approach for that, as it has very little overheads, and minimal impact on the application itself.
Any questions?
A hard-coded systemtap solution could look like:
% cat FOO.stp
global counts
probe process("/path/to/your/binary").function("CertainFunction") { counts[pid()] <<< 1 }
probe process("/path/to/your/binary").end { println ("pid %d count %sd", pid(), #count(counts[pid()]))
delete counts[pid()] }
# stap FOO.stp
pid 42323 count 112
pid 2123 count 0
... etc, until interrupted
Thanks for the responses. There is lots of good information in the other answers. However, here's what I did. First I tweaked the program to add a counter in a shm file:
struct StatsCounter {
char counterName[8];
unsigned long int counter;
};
StatsCounter * stats;
void initStatsCounter()
{
int fd = shm_open("TestStats", O_RDWR|O_CREAT, 0);
if (fd == -1)
{
syslog(priority, "%s:: Initialization Failed", __func__);
stats = (StatsCounter *) malloc(sizeof(StatsCounter));
}
else
{
// For now, just one StatsCounter is used, but it could become an array.
ftruncate(fd, sizeof(StatsCounter));
stats = (StatsCounter *) mmap(NULL, sizeof(StatsCounter),
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
}
// Initialize names. Pad them to 7 chars (save room for \0).
snprintf(stats[0].counterName, sizeof(stats[0].counterName), "nRespX ");
stats[0].counter = 0;
}
And changed processServerResponseX to increment stats[0].counter in the locked section. Then I changed the script to parse the shm file with "hexdump":
hexdump /dev/shm/TestStats -e ' 1/8 "%s " 1/8 "%d\n"'
This will then show something like this:
nRespX 23
This way I can extend this later if I want to also look at response Y, ...
Not sure if there are mutual exclusion problems with hexdump if it accessed the file while it was being changed. But in my case, I don't think it matters, because the script only calls it before and after the test, it should not be in the middle of an update.
I want to write a signal handler to catch SIGSEGV.
I protect a block of memory for read or write using
char *buffer;
char *p;
char a;
int pagesize = 4096;
mprotect(buffer,pagesize,PROT_NONE)
This protects pagesize bytes of memory starting at buffer against any reads or writes.
Second, I try to read the memory:
p = buffer;
a = *p
This will generate a SIGSEGV, and my handler will be called.
So far so good. My problem is that, once the handler is called, I want to change the access write of the memory by doing
mprotect(buffer,pagesize,PROT_READ);
and continue normal functioning of my code. I do not want to exit the function.
On future writes to the same memory, I want to catch the signal again and modify the write rights and then record that event.
Here is the code:
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
char *buffer;
int flag=0;
static void handler(int sig, siginfo_t *si, void *unused)
{
printf("Got SIGSEGV at address: 0x%lx\n",(long) si->si_addr);
printf("Implements the handler only\n");
flag=1;
//exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
char *p; char a;
int pagesize;
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
if (sigaction(SIGSEGV, &sa, NULL) == -1)
handle_error("sigaction");
pagesize=4096;
/* Allocate a buffer aligned on a page boundary;
initial protection is PROT_READ | PROT_WRITE */
buffer = memalign(pagesize, 4 * pagesize);
if (buffer == NULL)
handle_error("memalign");
printf("Start of region: 0x%lx\n", (long) buffer);
printf("Start of region: 0x%lx\n", (long) buffer+pagesize);
printf("Start of region: 0x%lx\n", (long) buffer+2*pagesize);
printf("Start of region: 0x%lx\n", (long) buffer+3*pagesize);
//if (mprotect(buffer + pagesize * 0, pagesize,PROT_NONE) == -1)
if (mprotect(buffer + pagesize * 0, pagesize,PROT_NONE) == -1)
handle_error("mprotect");
//for (p = buffer ; ; )
if(flag==0)
{
p = buffer+pagesize/2;
printf("It comes here before reading memory\n");
a = *p; //trying to read the memory
printf("It comes here after reading memory\n");
}
else
{
if (mprotect(buffer + pagesize * 0, pagesize,PROT_READ) == -1)
handle_error("mprotect");
a = *p;
printf("Now i can read the memory\n");
}
/* for (p = buffer;p<=buffer+4*pagesize ;p++ )
{
//a = *(p);
*(p) = 'a';
printf("Writing at address %p\n",p);
}*/
printf("Loop completed\n"); /* Should never happen */
exit(EXIT_SUCCESS);
}
The problem is that only the signal handler runs and I can't return to the main function after catching the signal.
When your signal handler returns (assuming it doesn't call exit or longjmp or something that prevents it from actually returning), the code will continue at the point the signal occurred, reexecuting the same instruction. Since at this point, the memory protection has not been changed, it will just throw the signal again, and you'll be back in your signal handler in an infinite loop.
So to make it work, you have to call mprotect in the signal handler. Unfortunately, as Steven Schansker notes, mprotect is not async-safe, so you can't safely call it from the signal handler. So, as far as POSIX is concerned, you're screwed.
Fortunately on most implementations (all modern UNIX and Linux variants as far as I know), mprotect is a system call, so is safe to call from within a signal handler, so you can do most of what you want. The problem is that if you want to change the protections back after the read, you'll have to do that in the main program after the read.
Another possibility is to do something with the third argument to the signal handler, which points at an OS and arch specific structure that contains info about where the signal occurred. On Linux, this is a ucontext structure, which contains machine-specific info about the $PC address and other register contents where the signal occurred. If you modify this, you change where the signal handler will return to, so you can change the $PC to be just after the faulting instruction so it won't re-execute after the handler returns. This is very tricky to get right (and non-portable too).
edit
The ucontext structure is defined in <ucontext.h>. Within the ucontext the field uc_mcontext contains the machine context, and within that, the array gregs contains the general register context. So in your signal handler:
ucontext *u = (ucontext *)unused;
unsigned char *pc = (unsigned char *)u->uc_mcontext.gregs[REG_RIP];
will give you the pc where the exception occurred. You can read it to figure out what instruction it
was that faulted, and do something different.
As far as the portability of calling mprotect in the signal handler is concerned, any system that follows either the SVID spec or the BSD4 spec should be safe -- they allow calling any system call (anything in section 2 of the manual) in a signal handler.
You've fallen into the trap that all people do when they first try to handle signals. The trap? Thinking that you can actually do anything useful with signal handlers. From a signal handler, you are only allowed to call asynchronous and reentrant-safe library calls.
See this CERT advisory as to why and a list of the POSIX functions that are safe.
Note that printf(), which you are already calling, is not on that list.
Nor is mprotect. You're not allowed to call it from a signal handler. It might work, but I can promise you'll run into problems down the road. Be really careful with signal handlers, they're tricky to get right!
EDIT
Since I'm being a portability douchebag at the moment already, I'll point out that you also shouldn't write to shared (i.e. global) variables without taking the proper precautions.
You can recover from SIGSEGV on linux. Also you can recover from segmentation faults on Windows (you'll see a structured exception instead of a signal). But the POSIX standard doesn't guarantee recovery, so your code will be very non-portable.
Take a look at libsigsegv.
You should not return from the signal handler, as then behavior is undefined. Rather, jump out of it with longjmp.
This is only okay if the signal is generated in an async-signal-safe function. Otherwise, behavior is undefined if the program ever calls another async-signal-unsafe function. Hence, the signal handler should only be established immediately before it is necessary, and disestablished as soon as possible.
In fact, I know of very few uses of a SIGSEGV handler:
use an async-signal-safe backtrace library to log a backtrace, then die.
in a VM such as the JVM or CLR: check if the SIGSEGV occurred in JIT-compiled code. If not, die; if so, then throw a language-specific exception (not a C++ exception), which works because the JIT compiler knew that the trap could happen and generated appropriate frame unwind data.
clone() and exec() a debugger (do not use fork() – that calls callbacks registered by pthread_atfork()).
Finally, note that any action that triggers SIGSEGV is probably UB, as this is accessing invalid memory. However, this would not be the case if the signal was, say, SIGFPE.
There is a compilation problem using ucontext_t or struct ucontext (present in /usr/include/sys/ucontext.h)
http://www.mail-archive.com/arch-general#archlinux.org/msg13853.html