Topic: SUM: exceptions and C/C++ mixing
Author: Yannick de Kercadio <kercadio@limsi.fr>
Date: 1999/05/06 Raw View
We would like to thank Steve Clamage and James Kuyper for their valuable
answers. This is a summary of our problem and of the solutions.
Our problem was error handling in C++ while calling some API (Oracle
database, using ESQL C) in C. The main difficulty was that we had to
return error strings of unpredictable size, this size being available
only to C code. However, we wanted to report these strings in some C++
exceptions.
A setjmp/longjmp solution is very tedious. There should not be any C++
code executed between setjmp and longjmp. This is because C++ can
allocate objects that would not be destroyed when 'longjumping'.
However, our setjmp/longjmp limited the range of the jump to a C score,
no C++ code being involved between them. The solution proved to be not
satisfactory, because we had to allocate some memory for the error
strings in C (using malloc()). Such memory should be freed by free(), so
we decided to implement a C function to free this memory.
/* in C */
static char *error_str;
static size_t error_length;
static jump_buf my_buffer;
void error_handling(char **ret)
{
*ret = (char *)malloc(error_length + 1);
strncpy(*ret, error_str, error_length);
ret[error_length] = '\0';
}
void free_error(char *ret)
{
free(ret);
}
void my_error_fn()
{
error_str = the_str;
error_length = the_len;
longjmp(my_buffer, 1);
}
int query(char *request)
{
if(setjmp(my_buffer))
return 1;
EXEC SQL WHENEVER SQLERROR DO my_error_fn();
/* calling SQL parser and so on */
return 0;
}
// in C++
extern "C" {
#include "my_C_oracle_header.h"
}
void sql::query(const string &request)
{
// calling C code
if(query(request.c_str()))
{
char *temp;
error_handling(&temp);
runtime_error e(temp); // this may cause a core dump!
free_error(temp);
throw(e);
}
}
The line marked as causing a core dump (at least with g++ 2.8.1 on IRIX
5.3) did so under certain circumstances (memory almost full). It seems
that there is a conflict between the C++ allocation (for runtime_error)
and the C free().
Both Steve Clamage and James Kuyper suggested to use a callback
function, writen in C++, but linked as a C function.
/* in C */
static void (*static_error_handler)(const char *, size_t, void *);
static void *parameter;
void my_error_fn()
{
static_error_handler(the_str, the_len, param);
}
void query(char *request, void (*error_hndl)(const char *, size_t,
void *), void *param)
{
static_error_handler = error_hndl;
parameter = param;
EXEC SQL WHENEVER SQLERROR DO my_error_fn();
/* calling SQL parser and so on */
}
// in C++
extern "C" {
#include "my_C_oracle_header.h"
}
extern "C" void my_error_handler(const char *str, size_t len,
void *p)
{
((sql *)p)->handle_error(str, len);
}
void sql::handle_error(const char *str, size_t len)
{
my_error_str = string(str, len);
my_error_flag = true;
}
void sql::query(const string &request)
{
my_error_flag = false;
// calling C code
query(request.c_str(), &my_error_handler, this);
if(my_error_flag)
throw(runtime_error(my_error_str));
}
It is really much better! It is not thread-safe, but no database access
is thread-safe, anyway... So it works perfectly for our needs.
Thanks again to S. Clamage and J. Kuyper. We hope that this message
could help other people who have to integrate C code into a C++
application.
--
Yannick de Kercadio
kercadio@limsi.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]