logo       

Re: C++ exceptions: msg#00032

gnu.cegcc.devel

Subject: Re: C++ exceptions

Kevin O'Connor wrote:
On Thu, Jul 05, 2007 at 02:54:33AM +0100, Pedro Alves wrote:

(...)
Very nice. Hiding the __ehd would be great. If not possible
then I suggest at least adding ##__LINE__ to it.

I suppose one could do something like:

#define TRY_SEH \
do { \
struct eh_data __ehd; \
int __ret = setjmp(__ehd.env); \
if (!__ret) { \
start_ehandling(&__ehd);

#define CATCH_SEH \
end_ehandling(&__ehd); \
} else {

#define END_SEH \
} \
} while (0);


(...)

This has the advantage that it should work with C code. (I'm pretty
sure you could hide __ehd and not require an END decl with C++, but it
would look ugly and not be significantly better than the previous
implementation.)


Yep, I agree that C support is important.

Earlier on, I tried to use the same __try/__except syntax that msdn
documents. However, I gave up on it - it was too complicated and not
useful for me. In particular, implementing __finally would be
painful.


But what is life without pain? Oh well, it gets hidden under some
macros, so why not? :)

Checkout the attached. Not pretty and easy to follow, but it works, and
it allows stuff like:

__TRY
{
int *zero;
int result;

zero = 0;
result = *zero + *zero;
}
__EXCEPT_FILT (custom_filter)
{
printf ("except block with filter\n");
}
__END_TRY

or:

__TRY
{
int *zero;
int result;

zero = 0;
result = *zero + *zero;
}
__EXCEPT
{
printf ("except block without filter\n");
}
__END_TRY

or:

__TRY
{
printf ("normal try block\n");
}
__FINALLY
{
printf ("finally block\n");
}
__END_TRY


Better for portability with MSVC, where one can:

#ifdef _MSVC
#define __TRY __try
#define __FINALLY __finally
#define __EXCEPT_FILT(FILT) __except(FILT)
#define __EXCEPT __except
#else
...
#endif

(humm, in fact it could go in the exceptions.h headers.)

In the tar.gz, there is also the test_eh.cc compiled so if for some
reason you can't build it, at least you can try it in your device.

>I still don't know why I can't leave the exception handler with
>EXCEPTION_CONTINUE_EXECUTION..

Somewhat my fault for hinting wrongly. You should return with
ExceptionContinueExecution which comes from the following enum:

typedef enum {
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;

While these are to be used as the result of the __except
filter expression:

#define EXCEPTION_EXECUTE_HANDLER 1
#define EXCEPTION_CONTINUE_EXECUTION (-1)
#define EXCEPTION_CONTINUE_SEARCH 0

I think the global helper functions exported could be renamed to have
a similar naming like a common prefix, or whatever.

--
Cheers,
Pedro Alves

#ifndef SEH_EXCEPTIONS_H
#define SEH_EXCEPTIONS_H

#include <setjmp.h>
#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef int (*__seh_filter) (unsigned int code, struct _EXCEPTION_POINTERS *ep);

struct eh_data {
jmp_buf env;
__seh_filter filter;
};

#define __TRY \
do { \
struct eh_data __ehd; \
memset (&__ehd, 0, sizeof (__ehd)); \
int __in_else = 1; \
int __in_finally = 0; \
(void)__in_finally; \
while (1) \
if (!__in_else) { \
do {

#define __EXCEPT_FILT(func) \
} while(0); \
end_ehandling(&__ehd); \
break; \
} else { \
__ehd.filter = (func); \
start_ehandling(&__ehd); \
if (setjmp(__ehd.env)) { \
end_ehandling(&__ehd); \
do {

#define __FINALLY \
} while(0); \
end_ehandling(&__ehd); \
__in_finally = 1; \
__in_else = 1; \
} else { \
if (!__in_finally) { \
__ehd.filter = eh_default_filter; \
start_ehandling(&__ehd); \
} \
if (__in_finally || setjmp(__ehd.env)) { \
end_ehandling(&__ehd); \
do {

#define __END_TRY \
} while (0); \
break; \
} \
__in_else = 0; \
} \
} while (0);

#define __EXCEPT __EXCEPT_FILT(eh_default_filter)

void start_ehandling(struct eh_data *d);
void end_ehandling(struct eh_data *d);
void init_thread_ehandling(void);
void init_ehandling(void);
int eh_default_filter(unsigned int code, struct _EXCEPTION_POINTERS *ep);

#ifdef __cplusplus
}
#endif

#endif

#include <windows.h>

#include "exceptions.h"

#define UNUSED __attribute__((unused))

static DWORD handler_tls;

void
start_ehandling(struct eh_data *d)
{
TlsSetValue(handler_tls, d);
}

void
end_ehandling(struct eh_data *d UNUSED)
{
TlsSetValue(handler_tls, NULL);
}

void
init_thread_ehandling(void)
{
TlsSetValue(handler_tls, NULL);
}

void
init_ehandling(void)
{
handler_tls = TlsAlloc();
}

struct _DISPATCHER_CONTEXT;

EXCEPTION_DISPOSITION
eh_handler(struct _EXCEPTION_RECORD *ExceptionRecord,
void *EstablisherFrame UNUSED,
struct _CONTEXT *ContextRecord,
struct _DISPATCHER_CONTEXT *DispatcherContext UNUSED)
{
struct eh_data *d = TlsGetValue(handler_tls);


if (d == NULL)
/* Unexpected, perhaps there is another handler installed. */
return EXCEPTION_CONTINUE_SEARCH;

if (d->filter)
{
int ret;
struct _EXCEPTION_POINTERS ep;
ep.ExceptionRecord = ExceptionRecord;
ep.ContextRecord = ContextRecord;
ret = d->filter (ExceptionRecord->ExceptionCode, &ep);

switch (ret)
{
case EXCEPTION_EXECUTE_HANDLER:
ContextRecord->Pc = (DWORD)longjmp;
ContextRecord->R0 = (DWORD)d->env;
ContextRecord->R1 = 1;
return ExceptionContinueExecution;

case EXCEPTION_CONTINUE_EXECUTION:
return ExceptionContinueExecution;

case EXCEPTION_CONTINUE_SEARCH:
default:
return ExceptionContinueSearch;
}
}

/* Unexpected, perhaps there is another handler installed. */
return EXCEPTION_CONTINUE_SEARCH;
}

int eh_default_filter(unsigned int code UNUSED, struct _EXCEPTION_POINTERS *ep
UNUSED)
{
return EXCEPTION_EXECUTE_HANDLER;
}

__asm__(
/* Data to be placed at start of .text section. The .init section
is placed before .text with the default linker script. */
"\t.section .init\n"
"\t.word eh_handler\n"
"\t.word 0\n"
"start_eh_text:\n"

/* Data for exception handler. */
"\t.section .pdata\n"
"\t.word start_eh_text\n"
"\t.word 0xc0000002 | (0xFFFFF << 8)\n" /* max 22 bits for number of
instructions */

/* Switch back. */
"\t.text\n"
);

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#include "exceptions.h"

static int custom_filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
printf("in custom_filter\n");

printf("Exception: Code:%x Flags:%x Addr:%x "
"SP:%x LR:%x R0:%x R1:%x R2:%x R3:%x R4:%x R5:%x R12:%x\n\n",
code,
(unsigned)ep->ExceptionRecord->ExceptionFlags,
(unsigned)ep->ExceptionRecord->ExceptionAddress,
(unsigned)ep->ContextRecord->Sp,
(unsigned)ep->ContextRecord->Lr,
(unsigned)ep->ContextRecord->R0,
(unsigned)ep->ContextRecord->R1,
(unsigned)ep->ContextRecord->R2,
(unsigned)ep->ContextRecord->R3,
(unsigned)ep->ContextRecord->R4,
(unsigned)ep->ContextRecord->R5,
(unsigned)ep->ContextRecord->R12
);

return EXCEPTION_EXECUTE_HANDLER;
}

static void bad()
{
int *zero;
int result;

zero = 0;
result = *zero + *zero;
}

void test_eh (int i)
{
printf ("test 1\n");

printf ("arg i = %d\n", i);

__TRY
{
bad();
}
__EXCEPT
{
printf ("except block 1 reached\n");
}
__END_TRY

__TRY
{
int *zero;
int result;

zero = 0;
result = *zero + *zero;
}
__EXCEPT_FILT (custom_filter)
{
printf ("except block 2 reached\n");
}
__END_TRY

printf ("arg i = %d\n", i);

printf ("test 2\n");

__TRY
{
printf ("normal try block\n");
}
__FINALLY
{
printf ("in finally (1)\n");
}
__END_TRY

printf ("arg i = %d\n", i);

printf ("test 3\n");

__TRY
{
printf ("bad try block\n");

bad();

printf ("bad try block ended ?\n");
}
__FINALLY
{
printf ("in finally (2)\n");
}
__END_TRY

printf ("arg i = %d\n", i);

printf ("tests done\n");
}

int
main ()
{
init_ehandling();

test_eh (123);

return 0;
}

TARGET=arm-wince-mingw32ce
CC=$(TARGET)-gcc
CXX=$(TARGET)-g++

WARNFLAGS=-Wall -Wextra

#CFLAGS=-g0 -O0

CXXFLAGS=$(CFLAGS)

ALLCFLAGS=$(WARNFLAGS) $(CFLAGS)
ALLCXXFLAGS=$(WARNFLAGS) $(CXXFLAGS)

SOURCES=test_eh.cc Makefile exceptions.c exceptions.h
OBJECTS=test_eh.o exceptions.o

all: test_eh.exe

clean:
rm -f $(OBJECTS) test_eh.exe

test_eh.exe: $(OBJECTS)
$(CXX) $(OBJECTS) -o $@ $(ALLCXXFLAGS) $(LDFLAGS)

exceptions.o: exceptions.c exceptions.h
test_eh.o: test_eh.cc exceptions.h

.c.o:
$(CC) -c $< -o $@ $(ALLCFLAGS)

.cpp.o:
$(CXX) -c $< -o $@ $(ALLCXXFLAGS)

.cc.o:
$(CXX) -c $< -o $@ $(ALLCXXFLAGS)

download: test_eh.exe
pcp test_eh.exe ":/test_eh.exe"

dist: test_eh.tar.gz

test_eh.tar.gz: all $(SOURCES)
rm -f $@
tar cfz $@ $(SOURCES) test_eh.exe

Attachment: test_eh.tar.gz
Description: application/gzip

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/_______________________________________________
Cegcc-devel mailing list
Cegcc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@xxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/cegcc-devel
<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise