[OCaml] Some exception improvements

The OCaml module's exception handling code was poorly designed,
gave confusing exception messages, and was vulnerable to buffer
overflows.

The OCaml module's SWIG_exception_() was adding a useless newline to
the end of the exception message.

In some cases, the integer value of f.e. SWIG_TypeError was being added
to the exception message.

The unneeded else in the OCaml module's SWIG_contract_assert() macro
was causing -Wmisleading-indentation warnings.

The OCaml module's exception handling code now mirrors that of the
Java module.

Add Lib/ocaml/std_except.i.
Add multiple runtime tests.
This commit is contained in:
Zackery Spytz 2019-02-07 16:25:10 -07:00
commit e5b8b5a164
12 changed files with 264 additions and 41 deletions

View file

@ -127,13 +127,44 @@ SWIGINTERN void SWIG_JavaException(JNIEnv *jenv, int code, const char *msg) {
#ifdef SWIGOCAML
%{
#define OCAML_MSG_BUF_LEN 1024
SWIGINTERN void SWIG_exception_(int code, const char *msg) {
char msg_buf[OCAML_MSG_BUF_LEN];
sprintf( msg_buf, "Exception(%d): %s\n", code, msg );
caml_failwith( msg_buf );
SWIGINTERN void SWIG_OCamlException(int code, const char *msg) {
CAMLparam0();
SWIG_OCamlExceptionCodes exception_code = SWIG_OCamlUnknownError;
switch (code) {
case SWIG_DivisionByZero:
exception_code = SWIG_OCamlArithmeticException;
break;
case SWIG_IndexError:
exception_code = SWIG_OCamlIndexOutOfBoundsException;
break;
case SWIG_IOError:
case SWIG_SystemError:
exception_code = SWIG_OCamlSystemException;
break;
case SWIG_MemoryError:
exception_code = SWIG_OCamlOutOfMemoryError;
break;
case SWIG_OverflowError:
exception_code = SWIG_OCamlOverflowException;
break;
case SWIG_RuntimeError:
exception_code = SWIG_OCamlRuntimeException;
break;
case SWIG_SyntaxError:
case SWIG_TypeError:
case SWIG_ValueError:
exception_code = SWIG_OCamlIllegalArgumentException;
break;
case SWIG_UnknownError:
default:
exception_code = SWIG_OCamlUnknownError;
break;
}
SWIG_OCamlThrowException(exception_code, msg);
CAMLreturn0;
}
#define SWIG_exception(a,b) SWIG_exception_((a),(b))
#define SWIG_exception(code, msg) SWIG_OCamlException(code, msg)
%}
#endif

View file

@ -127,7 +127,44 @@ CAMLextern int64 Int64_val(caml_value_t v);
#define SWIG_GetModule(clientdata) SWIG_Ocaml_GetModule(clientdata)
#define SWIG_SetModule(clientdata, pointer) SWIG_Ocaml_SetModule(pointer)
#define SWIG_contract_assert(expr, msg) if(!(expr)) {caml_failwith(msg);} else
typedef enum {
SWIG_OCamlArithmeticException,
SWIG_OCamlDirectorPureVirtual,
SWIG_OCamlOutOfMemoryError,
SWIG_OCamlOverflowException,
SWIG_OCamlIllegalArgumentException,
SWIG_OCamlIndexOutOfBoundsException,
SWIG_OCamlRuntimeException,
SWIG_OCamlSystemException,
SWIG_OCamlUnknownError
} SWIG_OCamlExceptionCodes;
SWIGINTERN void SWIG_OCamlThrowException(SWIG_OCamlExceptionCodes code, const char *msg) {
CAMLparam0();
SWIG_CAMLlocal1(str);
switch (code) {
case SWIG_OCamlIllegalArgumentException:
caml_invalid_argument(msg);
break;
case SWIG_OCamlSystemException:
str = caml_copy_string(msg);
caml_raise_sys_error(str);
break;
case SWIG_OCamlArithmeticException:
case SWIG_OCamlIndexOutOfBoundsException:
case SWIG_OCamlOutOfMemoryError:
case SWIG_OCamlOverflowException:
case SWIG_OCamlRuntimeException:
case SWIG_OCamlUnknownError:
default:
caml_failwith(msg);
break;
}
CAMLreturn0;
}
#define SWIG_contract_assert(expr, msg) if(!(expr)) {SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, msg);}
SWIGINTERN int
SWIG_GetPtr(void *source, void **result, swig_type_info *type, swig_type_info *result_type);

23
Lib/ocaml/std_except.i Normal file
View file

@ -0,0 +1,23 @@
%{
#include <typeinfo>
#include <stdexcept>
%}
namespace std
{
%ignore exception;
struct exception {};
}
%typemap(throws) std::bad_cast "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::bad_exception "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::domain_error "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::exception "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::invalid_argument "SWIG_OCamlThrowException(SWIG_OCamlIllegalArgumentException, $1.what());"
%typemap(throws) std::length_error "SWIG_OCamlThrowException(SWIG_OCamlIndexOutOfBoundsException, $1.what());"
%typemap(throws) std::logic_error "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::out_of_range "SWIG_OCamlThrowException(SWIG_OCamlIndexOutOfBoundsException, $1.what());"
%typemap(throws) std::overflow_error "SWIG_OCamlThrowException(SWIG_OCamlArithmeticException, $1.what());"
%typemap(throws) std::range_error "SWIG_OCamlThrowException(SWIG_OCamlIndexOutOfBoundsException, $1.what());"
%typemap(throws) std::runtime_error "SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1.what());"
%typemap(throws) std::underflow_error "SWIG_OCamlThrowException(SWIG_OCamlArithmeticException, $1.what());"

View file

@ -163,19 +163,16 @@
unsigned int,
unsigned long,
unsigned short {
SWIG_exception($1,"Thrown exception from C++ (int)");
char error_msg[256];
sprintf(error_msg, "C++ $1_type exception thrown, value: %d", $1);
SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, error_msg);
}
%typemap(throws) SWIGTYPE CLASS {
$&1_ltype temp = new $1_ltype($1);
SWIG_exception((int)temp,"Thrown exception from C++ (object)");
}
%typemap(throws) SWIGTYPE {
%typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE *, SWIGTYPE [], SWIGTYPE [ANY] {
(void)$1;
SWIG_exception(0,"Thrown exception from C++ (unknown)");
SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, "C++ $1_type exception thrown");
}
%typemap(throws) char * {
SWIG_exception(0,$1);
SWIG_OCamlThrowException(SWIG_OCamlRuntimeException, $1);
}

View file

@ -19,7 +19,7 @@
* a new std_except.i file in the target library directory.
* ----------------------------------------------------------------------------- */
#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGGUILE) || defined(SWIGUTL) || defined(SWIGD)
#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGGUILE) || defined(SWIGUTL) || defined(SWIGD) || defined(SWIGOCAML)
#error "This version of std_except.i should not be used"
#endif