throw, catch, sigaction macosx - java-native-interface

The code pasted here is an attempt to map a SIGSEGV to a java exception. Before anyone gets too excited, yes, I know, this trangresses various statements in various standards. It's intended as an entirely temporary tactic to track down a stubborn bug.
On a Mac, at least, it doesn't work. the C++ throw in the sigaction function calls terminate.
I post this question to ask if anyone knows how to tweak this to work.
#include <stdio.h>
#include <signal.h>
#include "com_github_bimargulies_jnisigsegv_Native.h"
static JavaVM* staticJvm;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
staticJvm = jvm;
return JNI_VERSION_1_6;
}
/* there has to be a catch. */
struct SomethingToThrow {};
void handler_function(int sig, struct __siginfo* si, void *) {
JNIEnv *env = 0;
staticJvm->GetEnv((void **)&env, JNI_VERSION_1_6);
jclass newExcCls = env->FindClass("java/lang/RuntimeException");
env->ThrowNew(newExcCls, "SIGSEGV");
fprintf(stderr, "About to throw at the catch ... block\n");
fflush(stderr);
throw SomethingToThrow();
}
JNIEXPORT void JNICALL Java_com_github_bimargulies_jnisigsegv_Native_setupHandler(JNIEnv *, jclass) {
struct sigaction sa;
struct sigaction oldsa;
sa.sa_sigaction = handler_function;
sa.sa_mask = 0;
sa.sa_flags = SA_SIGINFO;
int r = sigaction(SIGSEGV, &sa, &oldsa);
fprintf(stderr, "Signaction returned %d\n", r);
fflush(stderr);
}
JNIEXPORT void JNICALL Java_com_github_bimargulies_jnisigsegv_Native_getAnError
(JNIEnv *, jclass, jstring) {
/* First experiment, just get a sigsegv */
char * p = 0;
try {
*p = 1;
} catch (...) {
fprintf(stderr, "Caught something\n");
}
return;
}

Take a look at the native bits of JNA, which uses setjmp/longjmp to translate SIGSEGV into a Java exception.
https://github.com/twall/jna/blob/master/native/protect.h
Note that when you start adding your own signal handlers, you need to properly chain signals normally handled by the VM (see http://download.oracle.com/javase/6/docs/technotes/guides/vm/signal-chaining.html).
You should read carefully the man pages for sigaction to review what you should and should not do within a signal handler. There are only a few system calls that are "safe", and I don't recall seeing anything about throwing C++ exceptions from the context of the signal handler being a supported operation. It's quite possible that your C++ exception stack unwind information may not be valid or accessible in the context of the signal handler.

Related

How to correctly handle SIGBUS so I can continue to search an address?

I'm currently working on a project running on a heavily modified version of Linux patched to be able to access a VMEbus. Most of the bus-handling is done, I have a VMEAccess class that uses mmap to write at a specific address of /dev/mem so a driver can pull that data and push it onto the bus.
When the program starts, it has no idea where the slave board it's looking for is located on the bus so it must find it by poking around: it tries to read every address one by one, if a device is connected there the read method returns some data but if there isn't anything connected a SIGBUS signal will be sent to the program.
I tried several solutions (mostly using signal handling) but after some time, I decided on using jumps. The first longjmp() call works fine but the second call to VMEAccess::readWord() gives me a Bus Error even though my handler should prevent the program from crashing.
Here's my code:
#include <iostream>
#include <string>
#include <sstream>
#include <csignal>
#include <cstdlib>
#include <csignal>
#include <csetjmp>
#include "types.h"
#include "VME_access.h"
VMEAccess *busVME;
int main(int argc, char const *argv[]);
void catch_sigbus (int sig);
void exit_function(int sig);
volatile BOOL bus_error;
volatile UDWORD offset;
jmp_buf env;
int main(int argc, char const *argv[])
{
sigemptyset(&sigBusHandler.sa_mask);
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = exit_function;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
/* */
struct sigaction sigBusHandler;
sigBusHandler.sa_handler = catch_sigbus;
sigemptyset(&sigBusHandler.sa_mask);
sigBusHandler.sa_flags = 0;
sigaction(SIGBUS, &sigBusHandler, NULL);
busVME = new VMEAccess(VME_SHORT);
offset = 0x01FE;
setjmp(env);
printf("%d\n", sigismember(&sigBusHandler.sa_mask, SIGBUS));
busVME->readWord(offset);
sleep(1);
printf("%#08x\n", offset+0xC1000000);
return 0;
}
void catch_sigbus (int sig)
{
offset++;
printf("%#08x\n", offset);
longjmp(env, 1);
}
void exit_function(int sig)
{
delete busVME;
exit(0);
}
As mentioned in the comments, using longjmp in a signal handler is a bad idea. After doing the jump out of a signal handler your program is effectively still in the signal handler. So calling non-async-signal-safe functions leads to undefined behavior for example. Using siglongjmp won't really help here, quoting man signal-safety:
If a signal handler interrupts the execution of an unsafe function, and the handler terminates via a call to longjmp(3) or siglongjmp(3) and the program subsequently calls an unsafe function, then the behavior of the program is undefined.
And just for example, this (siglongjmp) did cause some problems in libcurl code in the past, see here: error: longjmp causes uninitialized stack frame
I'd suggest to use a regular loop and modify the exit condition in the signal handler (you modify the offset there anyway) instead. Something like the following (pseudo-code):
int had_sigbus = 0;
int main(int argc, char const *argv[])
{
...
for (offset = 0x01FE; offset is sane; ++offset) {
had_sigbus = 0;
probe(offset);
if (!had_sigbus) {
// found
break;
}
}
...
}
void catch_sigbus(int)
{
had_sigbus = 1;
}
This way it's immediately obvious that there is a loop, and the whole logic is much easier to follow. And there are no jumps, so it should work for more than one probe :) But obviously probe() must handle the failed call (the one interrupted with SIGBUS) internally too - and probably return an error. If it does return an error using the had_sigbus function might be not necessary at all.

System exception handling on different platforms

Basically, how to catch exceptions on mac/linux? That is, exceptions, that are not intrinsic to the language, like segfaults & integer division. Compiling on MSVC, __try __except is perfect because the stack handling allows to catch exceptions and continue execution lower down the stack.
Now, i would like to extend my program to other platforms (mainly the ones mentioned), but i have no idea how exception handling works on these platforms work. As far as i understand, it's handled through posix signals? And as of such, wont allow to handle exception and continue lower down the stack?
Edit: Would this be valid (pseudo code)? As i see it, i leave C++ blocks correctly and thus dont indulge myself in UB.
jmp_buf buffer;
template< typename func >
protected_code(func f) {
if(!setjmp(buffer) {
f();
}
else
{
throw std::exception("exception happened in f()"):
}
}
void sig_handler() {
longjmp(buffer);
}
int main() {
sigaction(sig_handler);
try {
protected_code( [&]
{
1/0;
}
);
}
catch(const std::exception & e) {
...
}
}
Edit 2:
Wow for some reason i never thought of just throwing a C++ exception from the signal handler, no need to use longjmp/setjmp then. It of course relies on the fact that the thread calling the signal handler is the same stack and thread that faulted. Is this defined/guaranteed somewhere?
Code example:
void sig_handler(int arg) {
throw 4;
}
int main() {
signal(SIGFPE, sig_handler);
try {
int zero = 1;
zero--;
int ret = 1/zero;
} catch(int x) {
printf("catched %d\n", x);
}
return 0;
}
In Unix, you'd catch processor faults with signal handlers, using the sigaction function to install a suitable handler for the signal that you want to handle.
(I think you mean __try ... __except rather than __try ... __catch.

Catch SIGBUS in C and C++

I want to catch SIGBUS, my code is shown below:
#include <stdlib.h>
#include <signal.h>
#include <iostream>
#include <stdio.h>
void catch_sigbus (int sig)
{
//std::cout << "SIGBUS" << std::endl;
printf("SIGBUS\n");
exit(-1);
}
int main(int argc, char **argv) {
signal (SIGBUS, catch_sigbus);
int *iptr;
char *cptr;
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
/* malloc() always provides aligned memory */
cptr = (char*)malloc(sizeof(int) + 1);
/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;
/* Dereference it as an int pointer, causing an unaligned access */
*iptr = 42;
return 0;
}
When I use printf, it can catch by calling catch_sigbus, but when I use cout, it cannot. So anybody could help me? I run on Ubuntu 12.04.
I have another question. When I catch SIGBUS, how can I get si_code? BUS_ADRALN/BUS_ADRERR/BUS_OBJERR
You can't use printf or cout in a signal handler. Nor can you call exit. You got lucky with printf this time, but you weren't as lucky with cout. If your program is in a different state maybe cout will work and printf won't. Or maybe neither, or both. Check the documentation of your operating system to see which functions are signal safe (if it exists, it's often very badly documented).
Your safest bet in this case is to call write to STDERR_FILENO directly and then call _exit (not exit, that one is unsafe in a signal handler). On some systems it's safe to call fprintf to stderr, but I'm not sure if glibc is one of them.
Edit: To answer your added question, you need to set up your signal handlers with sigaction to get the additional information. This example is as far as I'd go inside a signal handler, I included an alternative method if you want to go advanced. Notice that write is theoretically unsafe because it will break errno, but since we're doing _exit it will be safe in this particular case:
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void
bus_handler(int sig, siginfo_t *si, void *vuctx)
{
char buf[2];
#if 1
/*
* I happen to know that si_code can only be 1, 2 or 3 on this
* particular system, so we only need to handle one digit.
*/
buf[0] = '0' + si->si_code;
buf[1] = '\n';
write(STDERR_FILENO, buf, sizeof(buf));
#else
/*
* This is a trick I sometimes use for debugging , this will
* be visible in strace while not messing with external state too
* much except breaking errno.
*/
write(-1, NULL, si->si_code);
#endif
_exit(1);
}
int
main(int argc, char **argv)
{
struct sigaction sa;
char *cptr;
int *iptr;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = bus_handler;
sa.sa_flags = SA_SIGINFO;
sigfillset(&sa.sa_mask);
sigaction(SIGBUS, &sa, NULL);
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
/* malloc() always provides aligned memory */
cptr = (char*)malloc(sizeof(int) + 1);
/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;
/* Dereference it as an int pointer, causing an unaligned access */
*iptr = 42;
return 0;
}
According to your comment, you're trying to debug SIGBUS, and there's existing question about that already:
Debugging SIGBUS on x86 Linux
That lists a number of possible causes. But probably the most likely reason for SIGBUS is, you have memory corruption and it messes things up so you get SIGBUS later... So debugging the signal might not be helpful at nailing the bug. That being said, use debugger to catch the point in code where signal is thrown, and see if it is a pointer. That's a good starting point for trying to find out the cause.

In a signal handler, how to know where the program is interrupted?

On x86 (either 64-bit or 32-bit) Linux --
for example:
void signal_handler(int) {
// want to know where the program is interrupted ...
}
int main() {
...
signal(SIGALRM, signal_handler);
alarm(5);
...
printf(...); <------- at this point, we trigger signal_handler
...
}
In signal_handler, how can we know we are interrupted at printf in main()?
Use sigaction with SA_SIGINFO set in sa_flags.
Prototype code:
#define _GNU_SOURCE 1 /* To pick up REG_RIP */
#include <stdio.h>
#include <signal.h>
#include <assert.h>
static void
handler(int signo, siginfo_t *info, void *context)
{
const ucontext_t *con = (ucontext_t *)context;
/* I know, never call printf from a signal handler. Meh. */
printf("IP: %lx\n", con->uc_mcontext.gregs[REG_RIP]);
}
int
main(int argc, char *argv[])
{
struct sigaction sa = { };
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
assert(sigaction(SIGINT, &sa, NULL) == 0);
for (;;);
return 0;
}
Run it and hit Ctrl-C. (Use Ctrl-\ to terminate...)
This is for x86_64. For 32-bit x86, use REG_EIP instead of REG_RIP.
[edit]
Of course, if you are actually in a library function (like printf) or a system call (like write), the RIP/EIP register might point somewhere funny...
You might want to use libunwind to crawl the stack.
Depending on your OS / Platform, it could be in a variety of areas:
On the current stack a set number of registers deep
On an/the interrupt stack
Within some sort of callback associated with your signal routine...
Without having additional info, I don't think we can track this much further. Adding a C/C++ tag to your might generate more responses and views.
In signal_handler, how can we know we are interrupted at printf in main()?
You can't, at least not from a C, C++, or POSIX perspective. Your operating system may provide OS-specific calls that let you poke at the stack. That's more than a bit dubious, though.
With timer-based signals, which instruction triggered the signal is a toss of the coin.
Workaround idea: if there are only a small number of places which can trigger a signal handler or you are only interested in which bigger block it happened you could maintain that in a variable.
entered = 1; // or entered = ENTER_PRINTF1;
printf(....);

Catching wrong array reference in C++

How do I catch wrong array reference in C++? Why doesn't the following code work:
#include <exception>
int * problemNum = new int;
int (* p [100])() = {problem1, problem2, problem3};
...
try {
cout << (*p[*problemNum-1])();
}
catch (exception){
cout << "No such problem";
}
My compiler says: Unhandled exception at 0xcccccccc in Euler.exe: 0xC0000005: Access violation. when I initiate bad reference by inputting 0 as *problemNum.
alamar is right - C++ won't catch exceptions with this type of array.
Use an STL vector instead:
#include <exception>
#include <vector>
int * problemNum = new int;
std::vector<int(*)()> p;
p.push_back(problem1);
p.push_back(problem2);
p.push_back(problem3);
...
try {
cout << p.at(*problemNum-1)();
}
catch (exception){
cout << "No such problem";
}
Becauce C++ can't handle such errors with its exception mechanism.
See Defective C++ on that issue.
Use sigaction(2).
sigaction - examine and change a signal action
SYNOPSIS
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
DESCRIPTION
The sigaction() system call is used to change the action taken by a process on receipt of a specific
signal.
signum specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.
If act is non-null, the new action for signal signum is installed from act. If oldact is non-null,
the previous action is saved in oldact.
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
You need to catch SIGSEGV, you can attach your own handler (function which gets called when illegal memory access is performed).