[jit] Improvements to error-handling
David Malcolm
dmalcolm@redhat.com
Fri Oct 18 16:06:00 GMT 2013
Committed to dmalcolm/jit:
Add defensive checks at the API boundary to gracefully reject
various kinds of error.
gcc/jit/
* internal-api.c (gcc::jit::context::get_type): Improve error
message, and report the bogus value.
(gcc::jit::context::new_binary_op): Likewise.
(gcc::jit::context::new_comparison): Likewise.
(gcc::jit::context::set_str_option): Likewise.
(gcc::jit::context::set_int_option): Likewise.
(gcc::jit::context::set_bool_option): Likewise.
(gcc::jit::context::compile): Likewise, and make the errors
block the creation of result, rather than just the return
value of the client callback.
(gcc::jit::context::add_error): Add varargs and provide
implementation, calling into...
(gcc::jit::context::add_error_va): New.
* internal-api.h (GNU_PRINTF): New.
(gcc::jit::context::add_error): Add varargs and GNU_PRINTF
attribute macro.
(gcc::jit::context::add_error_va): New.
(gcc::jit::context::errors_occurred): New.
(gcc::jit::context::m_error_count): New.
(gcc::jit::function::get_kind): New.
* libgccjit.c (JIT_BEGIN_STMT): New.
(JIT_END_STMT): New.
(RETURN_VAL_IF_FAIL): New.
(RETURN_NULL_IF_FAIL): New.
(RETURN_IF_FAIL): New.
(RETURN_IF_NOT_INITIAL_CTXT): New.
(RETURN_NULL_IF_NOT_INITIAL_CTXT): New.
(RETURN_NULL_IF_NOT_CALLBACK_CTXT): New.
(RETURN_IF_NOT_FUNC_DEFINITION): New.
(RETURN_NULL_IF_NOT_FUNC_DEFINITION): New.
(jit_error): New.
(gcc_jit_context_set_code_factory): Use new error-checking
macros.
(ASSERT_WITHIN_CALLBACK): Remove.
(ASSERT_NOT_WITHIN_CALLBACK): Remove.
(gcc_jit_context_new_location): Use new error-checking macros.
(gcc_jit_context_get_type): Likewise.
(gcc_jit_type_get_pointer): Likewise.
(gcc_jit_type_get_const): Likewise.
(gcc_jit_context_new_field): Likewise.
(gcc_jit_context_new_struct_type): Likewise.
(gcc_jit_context_new_param): Likewise.
(gcc_jit_param_as_lvalue): Likewise.
(gcc_jit_param_as_rvalue): Likewise.
(gcc_jit_context_new_function): Likewise.
(gcc_jit_function_new_forward_label): Likewise.
(gcc_jit_context_new_global): Likewise.
(gcc_jit_lvalue_as_rvalue): Likewise.
(gcc_jit_context_new_rvalue_from_int): Likewise.
(gcc_jit_context_zero): Likewise.
(gcc_jit_context_one): Likewise.
(gcc_jit_context_new_rvalue_from_double): Likewise.
(gcc_jit_context_new_rvalue_from_ptr): Likewise.
(gcc_jit_context_new_string_literal): Likewise.
(gcc_jit_context_new_binary_op): Likewise.
(gcc_jit_context_new_comparison): Likewise.
(gcc_jit_context_new_call): Likewise.
(gcc_jit_context_new_array_lookup): Likewise.
(gcc_jit_context_new_field_access): Likewise.
(gcc_jit_function_new_local): Likewise.
(gcc_jit_function_add_label): Likewise.
(gcc_jit_function_place_forward_label): Likewise.
(gcc_jit_function_add_eval): Likewise.
(gcc_jit_function_add_assignment): Likewise.
(gcc_jit_function_add_assignment_op): Likewise.
(gcc_jit_function_add_conditional): Likewise.
(gcc_jit_function_add_jump): Likewise.
(gcc_jit_function_add_return): Likewise.
(gcc_jit_function_new_loop): Likewise.
(gcc_jit_loop_end): Likewise.
(gcc_jit_context_set_str_option): Likewise.
(gcc_jit_context_set_int_option): Likewise.
(gcc_jit_context_set_bool_option): Likewise.
(gcc_jit_context_compile): Likewise.
(gcc_jit_result_get_code): Likewise.
(gcc_jit_result_release): Likewise.
* libgccjit.h (gcc_jit_function_new_forward_label): Clarify
behavior.
(gcc_jit_function_add_label): Likewise.
gcc/testsuite/
* jit.dg/test-null-passed-to-api.c: New.
---
gcc/jit/ChangeLog.jit | 82 +++++++
gcc/jit/internal-api.c | 44 +++-
gcc/jit/internal-api.h | 28 ++-
gcc/jit/libgccjit.c | 299 +++++++++++++++++++++----
gcc/jit/libgccjit.h | 8 +-
gcc/testsuite/ChangeLog.jit | 4 +
gcc/testsuite/jit.dg/test-null-passed-to-api.c | 30 +++
7 files changed, 444 insertions(+), 51 deletions(-)
create mode 100644 gcc/testsuite/jit.dg/test-null-passed-to-api.c
diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 78c1b65..bcbb93b 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,85 @@
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::get_type): Improve error
+ message, and report the bogus value.
+ (gcc::jit::context::new_binary_op): Likewise.
+ (gcc::jit::context::new_comparison): Likewise.
+ (gcc::jit::context::set_str_option): Likewise.
+ (gcc::jit::context::set_int_option): Likewise.
+ (gcc::jit::context::set_bool_option): Likewise.
+ (gcc::jit::context::compile): Likewise, and make the errors
+ block the creation of result, rather than just the return
+ value of the client callback.
+ (gcc::jit::context::add_error): Add varargs and provide
+ implementation, calling into...
+ (gcc::jit::context::add_error_va): New.
+ * internal-api.h (GNU_PRINTF): New.
+ (gcc::jit::context::add_error): Add varargs and GNU_PRINTF
+ attribute macro.
+ (gcc::jit::context::add_error_va): New.
+ (gcc::jit::context::errors_occurred): New.
+ (gcc::jit::context::m_error_count): New.
+ (gcc::jit::function::get_kind): New.
+ * libgccjit.c (JIT_BEGIN_STMT): New.
+ (JIT_END_STMT): New.
+ (RETURN_VAL_IF_FAIL): New.
+ (RETURN_NULL_IF_FAIL): New.
+ (RETURN_IF_FAIL): New.
+ (RETURN_IF_NOT_INITIAL_CTXT): New.
+ (RETURN_NULL_IF_NOT_INITIAL_CTXT): New.
+ (RETURN_NULL_IF_NOT_CALLBACK_CTXT): New.
+ (RETURN_IF_NOT_FUNC_DEFINITION): New.
+ (RETURN_NULL_IF_NOT_FUNC_DEFINITION): New.
+ (jit_error): New.
+ (gcc_jit_context_set_code_factory): Use new error-checking
+ macros.
+ (ASSERT_WITHIN_CALLBACK): Remove.
+ (ASSERT_NOT_WITHIN_CALLBACK): Remove.
+ (gcc_jit_context_new_location): Use new error-checking macros.
+ (gcc_jit_context_get_type): Likewise.
+ (gcc_jit_type_get_pointer): Likewise.
+ (gcc_jit_type_get_const): Likewise.
+ (gcc_jit_context_new_field): Likewise.
+ (gcc_jit_context_new_struct_type): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_function_new_forward_label): Likewise.
+ (gcc_jit_context_new_global): Likewise.
+ (gcc_jit_lvalue_as_rvalue): Likewise.
+ (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+ (gcc_jit_context_new_string_literal): Likewise.
+ (gcc_jit_context_new_binary_op): Likewise.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_array_lookup): Likewise.
+ (gcc_jit_context_new_field_access): Likewise.
+ (gcc_jit_function_new_local): Likewise.
+ (gcc_jit_function_add_label): Likewise.
+ (gcc_jit_function_place_forward_label): Likewise.
+ (gcc_jit_function_add_eval): Likewise.
+ (gcc_jit_function_add_assignment): Likewise.
+ (gcc_jit_function_add_assignment_op): Likewise.
+ (gcc_jit_function_add_conditional): Likewise.
+ (gcc_jit_function_add_jump): Likewise.
+ (gcc_jit_function_add_return): Likewise.
+ (gcc_jit_function_new_loop): Likewise.
+ (gcc_jit_loop_end): Likewise.
+ (gcc_jit_context_set_str_option): Likewise.
+ (gcc_jit_context_set_int_option): Likewise.
+ (gcc_jit_context_set_bool_option): Likewise.
+ (gcc_jit_context_compile): Likewise.
+ (gcc_jit_result_get_code): Likewise.
+ (gcc_jit_result_release): Likewise.
+ * libgccjit.h (gcc_jit_function_new_forward_label): Clarify
+ behavior.
+ (gcc_jit_function_add_label): Likewise.
+
2013-10-17 David Malcolm <dmalcolm@redhat.com>
* internal-api.c (gcc::jit::context::get_void_type): Remove.
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index 9232215..c5376a3 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -136,7 +136,7 @@ get_type (enum gcc_jit_types type_)
tree type_node = get_tree_node_for_type (type_);
if (NULL == type_node)
{
- add_error ("unrecognized (enum gcc_jit_types) value");
+ add_error ("unrecognized (enum gcc_jit_types) value: %i", type_);
return NULL;
}
@@ -393,7 +393,10 @@ new_binary_op (location *loc,
switch (op)
{
- default: gcc_unreachable ();
+ default:
+ add_error ("unrecognized (enum gcc_jit_binary_op) value: %i", op);
+ return NULL;
+
case GCC_JIT_BINARY_OP_PLUS:
inner_op = PLUS_EXPR;
break;
@@ -431,7 +434,10 @@ new_comparison (location *loc,
switch (op)
{
- default: gcc_unreachable ();
+ default:
+ add_error ("unrecognized (enum gcc_jit_comparison) value: %i", op);
+ return NULL;
+
case GCC_JIT_COMPARISON_LT:
inner_op = LT_EXPR;
break;
@@ -916,7 +922,7 @@ set_str_option (enum gcc_jit_str_option opt,
{
if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
{
- add_error ("unrecognized str option");
+ add_error ("unrecognized (enum gcc_jit_str_option) value: %i", opt);
return;
}
m_str_options[opt] = value;
@@ -929,7 +935,7 @@ set_int_option (enum gcc_jit_int_option opt,
{
if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
{
- add_error ("unrecognized int option");
+ add_error ("unrecognized (enum gcc_jit_int_option) value: %i", opt);
return;
}
m_int_options[opt] = value;
@@ -942,7 +948,7 @@ set_bool_option (enum gcc_jit_bool_option opt,
{
if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
{
- add_error ("unrecognized bool option");
+ add_error ("unrecognized (enum gcc_jit_bool_option) value: %i", opt);
return;
}
m_bool_options[opt] = value ? true : false;
@@ -1013,7 +1019,8 @@ compile ()
switch (m_int_options[GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL])
{
default:
- add_error ("unrecognized optimization level");
+ add_error ("unrecognized optimization level: %i",
+ m_int_options[GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL]);
goto error;
case 0:
@@ -1074,7 +1081,7 @@ compile ()
active_jit_ctxt = NULL;
- if (m_cb_result)
+ if (errors_occurred ())
goto error;
timevar_push (TV_ASSEMBLE);
@@ -1151,7 +1158,7 @@ invoke_code_factory ()
m_within_code_factory = false;
timevar_pop (TV_CLIENT_CALLBACK);
- if (!m_cb_result)
+ if (!errors_occurred ())
{
int i;
function *func;
@@ -1266,9 +1273,24 @@ handle_locations ()
void
gcc::jit::context::
-add_error (const char */*msg*/)
+add_error (const char *fmt, ...)
{
- // TODO
+ va_list ap;
+ va_start (ap, fmt);
+ add_error_va (fmt, ap);
+ va_end (ap);
+}
+
+void
+gcc::jit::context::
+add_error_va (const char *fmt, va_list ap)
+{
+ char buf[1024];
+ vsnprintf (buf, sizeof (buf) - 1, fmt, ap);
+
+ error ("%s\n", buf);
+
+ m_error_count++;
}
gcc::jit::result::
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index b145cb3..6665e65 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -5,6 +5,14 @@
#include <utility> // for std::pair
+#ifdef GCC_VERSION
+#if GCC_VERSION >= 4001
+#define GNU_PRINTF(M, N) __attribute__ ((format (gnu_printf, (M), (N))))
+#else
+#define GNU_PRINTF(M, N)
+#endif
+#endif
+
namespace gcc {
namespace jit {
@@ -142,7 +150,12 @@ public:
within_code_factory () const { return m_within_code_factory; }
void
- add_error (const char *msg);
+ add_error (const char *fmt, ...)
+ GNU_PRINTF(2, 3);
+
+ void
+ add_error_va (const char *fmt, va_list ap)
+ GNU_PRINTF(2, 0);
void
set_tree_location (tree t, location *loc);
@@ -153,11 +166,22 @@ private:
void handle_locations ();
+
+ /* Did errors occur in the client callback (either recorded
+ by our internal checking, or reported by the client). */
+ bool errors_occurred () const
+ {
+ return m_error_count || m_cb_result;
+ }
+
+
private:
gcc_jit_code_callback m_code_factory;
bool m_within_code_factory;
void *m_user_data;
+ int m_error_count;
+
/* Allocated using xmalloc (by xstrdup). */
char *m_path_template;
@@ -259,6 +283,8 @@ public:
tree as_fndecl () const { return m_inner_fndecl; }
+ enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
lvalue *
new_local (location *loc,
type *type,
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 5da2889..05afd8e 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -52,6 +52,112 @@ struct gcc_jit_loop : public gcc::jit::loop
{
};
+/**********************************************************************
+ Error-handling.
+
+ We try to gracefully handle API usage errors by being defensive
+ at the API boundary.
+ **********************************************************************/
+
+#define JIT_BEGIN_STMT do {
+#define JIT_END_STMT } while(0)
+
+/* TODO: mark failure branches as unlikely? */
+
+#define RETURN_VAL_IF_FAIL(TEST_EXPR, RETURN_EXPR, CTXT, ERR_MSG) \
+ JIT_BEGIN_STMT \
+ if (!(TEST_EXPR)) \
+ { \
+ jit_error ((CTXT), "%s: %s", __func__, (ERR_MSG)); \
+ return (RETURN_EXPR); \
+ } \
+ JIT_END_STMT
+
+#define RETURN_NULL_IF_FAIL(TEST_EXPR, CTXT, ERR_MSG) \
+ RETURN_VAL_IF_FAIL ((TEST_EXPR), NULL, (CTXT), (ERR_MSG))
+
+#define RETURN_IF_FAIL(TEST_EXPR, CTXT, ERR_MSG) \
+ JIT_BEGIN_STMT \
+ if (!(TEST_EXPR)) \
+ { \
+ jit_error ((CTXT), "%s: %s", __func__, (ERR_MSG)); \
+ return; \
+ } \
+ JIT_END_STMT
+
+/* Check that CTXT is non-NULL, and that is is before the callback. */
+#define RETURN_IF_NOT_INITIAL_CTXT(CTXT) \
+ JIT_BEGIN_STMT \
+ RETURN_IF_FAIL ((CTXT), (CTXT), "NULL context"); \
+ RETURN_IF_FAIL (!(CTXT)->within_code_factory (), \
+ (CTXT), \
+ ("erroneously used within code factory" \
+ " callback")); \
+ JIT_END_STMT
+
+#define RETURN_NULL_IF_NOT_INITIAL_CTXT(CTXT) \
+ JIT_BEGIN_STMT \
+ RETURN_NULL_IF_FAIL ((CTXT), (CTXT), "NULL context"); \
+ RETURN_NULL_IF_FAIL (!(CTXT)->within_code_factory (), \
+ (CTXT), \
+ ("erroneously used within code factory" \
+ " callback")); \
+ JIT_END_STMT
+
+/* Check that CTXT is non-NULL, and that is is within the callback. */
+#define RETURN_NULL_IF_NOT_CALLBACK_CTXT(CTXT) \
+ JIT_BEGIN_STMT \
+ RETURN_NULL_IF_FAIL ((CTXT), (CTXT), "NULL context"); \
+ RETURN_NULL_IF_FAIL ((CTXT)->within_code_factory (), \
+ (CTXT), \
+ ("erroneously used outside of code factory" \
+ " callback")); \
+ JIT_END_STMT
+
+/* Check that FUNC is non-NULL, and that it's OK to add statements to
+ it. */
+#define RETURN_IF_NOT_FUNC_DEFINITION(FUNC) \
+ JIT_BEGIN_STMT \
+ RETURN_IF_FAIL ((FUNC), NULL, "NULL function"); \
+ RETURN_IF_FAIL ((FUNC)->get_kind () != GCC_JIT_FUNCTION_IMPORTED, \
+ NULL, \
+ "Cannot add code to an imported function"); \
+ JIT_END_STMT
+
+#define RETURN_NULL_IF_NOT_FUNC_DEFINITION(FUNC) \
+ JIT_BEGIN_STMT \
+ RETURN_NULL_IF_FAIL ((FUNC), NULL, "NULL function"); \
+ RETURN_NULL_IF_FAIL ((FUNC)->get_kind () != GCC_JIT_FUNCTION_IMPORTED,\
+ NULL, \
+ "Cannot add code to an imported function"); \
+ JIT_END_STMT
+
+static void
+jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
+ GNU_PRINTF(2, 3);
+
+static void
+jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+
+ /* If no context was given/known, try to report it on the active
+ context, if any. */
+ if (!ctxt)
+ ctxt = (gcc_jit_context *)gcc::jit::active_jit_ctxt;
+
+ if (ctxt)
+ ctxt->add_error_va (fmt, ap);
+ else
+ {
+ /* No context? Send to stderr. */
+ vfprintf (stderr, "%s\n", ap);
+ }
+
+ va_end (ap);
+}
+
gcc_jit_context *
gcc_jit_context_acquire (void)
{
@@ -69,30 +175,24 @@ gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
gcc_jit_code_callback cb,
void *user_data)
{
- gcc_assert (ctxt);
+ RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+ RETURN_IF_FAIL (cb, ctxt, "NULL callback");
+ /* user_data can be anything. */
+
ctxt->set_code_factory (cb, user_data);
}
/**********************************************************************
Functions for use within the code factory.
**********************************************************************/
-#define ASSERT_WITHIN_CALLBACK(CTXT) \
- do { \
- gcc_assert ((CTXT)->within_code_factory ()); \
- } while (0)
-
-#define ASSERT_NOT_WITHIN_CALLBACK(CTXT) \
- do { \
- gcc_assert (!(CTXT)->within_code_factory ()); \
- } while (0)
-
gcc_jit_location *
gcc_jit_context_new_location (gcc_jit_context *ctxt,
const char *filename,
int line,
int column)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+
return (gcc_jit_location *)ctxt->new_location (filename, line, column);
}
@@ -100,19 +200,27 @@ gcc_jit_type *
gcc_jit_context_get_type (gcc_jit_context *ctxt,
enum gcc_jit_types type)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ /* The inner function checks "type" for us. */
+
return (gcc_jit_type *)ctxt->get_type (type);
}
gcc_jit_type *
gcc_jit_type_get_pointer (gcc_jit_type *type)
{
+ RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
+ /* can't check for WITHIN_CALLBACK */
+
return (gcc_jit_type *)type->get_pointer ();
}
gcc_jit_type *
gcc_jit_type_get_const (gcc_jit_type *type)
{
+ RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
+ /* can't check for WITHIN_CALLBACK */
+
return (gcc_jit_type *)type->get_const ();
}
@@ -122,6 +230,10 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
gcc_jit_type *type,
const char *name)
{
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+
return (gcc_jit_field *)ctxt->new_field (loc, type, name);
}
@@ -132,6 +244,13 @@ gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
int num_fields,
gcc_jit_field **fields)
{
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+ if (num_fields)
+ RETURN_NULL_IF_FAIL (fields, ctxt, "NULL fields ptr");
+ for (int i = 0; i < num_fields; i++)
+ RETURN_NULL_IF_FAIL (fields[i], ctxt, "NULL field ptr");
+
return (gcc_jit_type *)ctxt->new_struct_type (loc, name, num_fields,
(gcc::jit::field **)fields);
}
@@ -144,19 +263,28 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt,
gcc_jit_type *type,
const char *name)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+
return (gcc_jit_param *)ctxt->new_param (loc, type, name);
}
gcc_jit_lvalue *
gcc_jit_param_as_lvalue (gcc_jit_param *param)
{
+ RETURN_NULL_IF_FAIL (param, NULL, "NULL param");
+ /* can't check for WITHIN_CALLBACK */
+
return (gcc_jit_lvalue *)param->as_lvalue ();
}
gcc_jit_rvalue *
gcc_jit_param_as_rvalue (gcc_jit_param *param)
{
+ RETURN_NULL_IF_FAIL (param, NULL, "NULL param");
+ /* can't check for WITHIN_CALLBACK */
+
return (gcc_jit_rvalue *)param->as_rvalue ();
}
@@ -170,7 +298,17 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
gcc_jit_param **params,
int is_variadic)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (return_type, ctxt, "NULL return_type");
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+ RETURN_NULL_IF_FAIL ((num_params == 0) || params, ctxt, "NULL params");
+ for (int i = 0; i < num_params; i++)
+ if (!params[i])
+ {
+ jit_error (ctxt, "%s: NULL parameter %i", __func__, i);
+ return NULL;
+ }
+
return (gcc_jit_function*)
ctxt->new_function (loc, kind, return_type, name,
num_params,
@@ -182,6 +320,10 @@ gcc_jit_label*
gcc_jit_function_new_forward_label (gcc_jit_function *func,
const char *name)
{
+ /* can't check for WITHIN_CALLBACK */
+ RETURN_NULL_IF_FAIL (func, NULL, "NULL function");
+ /* name can be NULL. */
+
return (gcc_jit_label *)func->new_forward_label (name);
}
@@ -191,13 +333,19 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
gcc_jit_type *type,
const char *name)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+ RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+
return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name);
}
gcc_jit_rvalue *
gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
{
+ RETURN_NULL_IF_FAIL (lvalue, NULL, "NULL lvalue");
+ /* can't check for WITHIN_CALLBACK */
+
return (gcc_jit_rvalue *)lvalue->as_rvalue ();
}
@@ -206,7 +354,9 @@ gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
gcc_jit_type *type,
int value)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (type, value);
}
@@ -214,7 +364,9 @@ gcc_jit_rvalue *
gcc_jit_context_zero (gcc_jit_context *ctxt,
gcc_jit_type *type)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
return gcc_jit_context_new_rvalue_from_int (ctxt, type, 0);
}
@@ -222,7 +374,9 @@ gcc_jit_rvalue *
gcc_jit_context_one (gcc_jit_context *ctxt,
gcc_jit_type *type)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
return gcc_jit_context_new_rvalue_from_int (ctxt, type, 1);
}
@@ -231,6 +385,9 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
gcc_jit_type *type,
double value)
{
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (type, value);
}
@@ -239,6 +396,9 @@ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
gcc_jit_type *type,
void *value)
{
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
return (gcc_jit_rvalue *)ctxt->new_rvalue_from_ptr (type, value);
}
@@ -246,11 +406,12 @@ gcc_jit_rvalue *
gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
const char *value)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (value, ctxt, "NULL value");
+
return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
}
-
gcc_jit_rvalue *
gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
gcc_jit_location *loc,
@@ -258,7 +419,12 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
gcc_jit_type *result_type,
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ /* op is checked by the inner function. */
+ RETURN_NULL_IF_FAIL (result_type, ctxt, "NULL result_type");
+ RETURN_NULL_IF_FAIL (a, ctxt, "NULL a");
+ RETURN_NULL_IF_FAIL (b, ctxt, "NULL b");
+
return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
}
@@ -268,18 +434,25 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
enum gcc_jit_comparison op,
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ /* op is checked by the inner function. */
+ RETURN_NULL_IF_FAIL (a, ctxt, "NULL a");
+ RETURN_NULL_IF_FAIL (b, ctxt, "NULL b");
+
return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
}
-
gcc_jit_rvalue *
gcc_jit_context_new_call (gcc_jit_context *ctxt,
gcc_jit_location *loc,
gcc_jit_function *func,
int numargs , gcc_jit_rvalue **args)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (func, ctxt, "NULL function");
+ if (numargs)
+ RETURN_NULL_IF_FAIL (args, ctxt, "NULL args");
+
return (gcc_jit_rvalue *)ctxt->new_call (loc,
func,
numargs,
@@ -292,7 +465,10 @@ gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
gcc_jit_rvalue *ptr,
gcc_jit_rvalue *index)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (ptr, ctxt, "NULL ptr");
+ RETURN_NULL_IF_FAIL (index, ctxt, "NULL index");
+
return (gcc_jit_rvalue *)ctxt->new_array_lookup (loc, ptr, index);
}
@@ -302,7 +478,10 @@ gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
gcc_jit_rvalue *ptr_or_struct,
const char *fieldname)
{
- ASSERT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+ RETURN_NULL_IF_FAIL (ptr_or_struct, ctxt, "NULL ptr_or_struct");
+ RETURN_NULL_IF_FAIL (fieldname, ctxt, "NULL fieldname");
+
return (gcc_jit_lvalue *)ctxt->new_field_access (loc, ptr_or_struct, fieldname);
}
@@ -312,7 +491,10 @@ gcc_jit_function_new_local (gcc_jit_function *func,
gcc_jit_type *type,
const char *name)
{
- ASSERT_WITHIN_CALLBACK (func->m_ctxt);
+ RETURN_NULL_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
+ RETURN_NULL_IF_FAIL (name, NULL, "NULL name");
+
return (gcc_jit_lvalue *)func->new_local (loc, type, name);
}
@@ -321,6 +503,9 @@ gcc_jit_function_add_label (gcc_jit_function *func,
gcc_jit_location *loc,
const char *name)
{
+ RETURN_NULL_IF_NOT_FUNC_DEFINITION (func);
+ /* loc and name can be NULL. */
+
return (gcc_jit_label *)func->add_label (loc, name);
}
@@ -329,6 +514,9 @@ gcc_jit_function_place_forward_label (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_label *lab)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (lab, NULL, "NULL label");
+
func->place_forward_label (loc, lab);
}
@@ -337,6 +525,9 @@ gcc_jit_function_add_eval (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_rvalue *rvalue)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+
return func->add_eval (loc, rvalue);
}
@@ -346,6 +537,10 @@ gcc_jit_function_add_assignment (gcc_jit_function *func,
gcc_jit_lvalue *lvalue,
gcc_jit_rvalue *rvalue)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (lvalue, NULL, "NULL lvalue");
+ RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+
return func->add_assignment (loc, lvalue, rvalue);
}
@@ -356,6 +551,11 @@ gcc_jit_function_add_assignment_op (gcc_jit_function *func,
enum gcc_jit_binary_op op,
gcc_jit_rvalue *rvalue)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (lvalue, NULL, "NULL lvalue");
+ /* op is checked by new_binary_op */
+ RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+
gcc_jit_type *type = (gcc_jit_type *)lvalue->get_type ();
gcc_jit_function_add_assignment (
func, loc,
@@ -374,6 +574,11 @@ gcc_jit_function_add_conditional (gcc_jit_function *func,
gcc_jit_label *on_true,
gcc_jit_label *on_false)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (boolval, NULL, "NULL boolval");
+ RETURN_IF_FAIL (on_true, NULL, "NULL on_true");
+ /* on_false can be NULL */
+
return func->add_conditional (loc, boolval, on_true, on_false);
}
@@ -382,6 +587,9 @@ gcc_jit_function_add_jump (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_label *target)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (target, NULL, "NULL target");
+
func->add_jump (loc, target);
}
@@ -390,6 +598,9 @@ gcc_jit_function_add_return (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_rvalue *rvalue)
{
+ RETURN_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+
return func->add_return (loc, rvalue);
}
@@ -398,6 +609,9 @@ gcc_jit_function_new_loop (gcc_jit_function *func,
gcc_jit_location *loc,
gcc_jit_rvalue *boolval)
{
+ RETURN_NULL_IF_NOT_FUNC_DEFINITION (func);
+ RETURN_NULL_IF_FAIL (boolval, NULL, "NULL boolval");
+
return (gcc_jit_loop *)func->new_loop (loc, boolval);
}
@@ -405,6 +619,8 @@ void
gcc_jit_loop_end (gcc_jit_loop *loop,
gcc_jit_location *loc)
{
+ RETURN_IF_FAIL (loop, NULL, "NULL loop");
+
loop->end (loc);
}
@@ -417,8 +633,10 @@ gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
enum gcc_jit_str_option opt,
const char *value)
{
- gcc_assert (ctxt);
- ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+ RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+ /* opt is checked by the inner function.
+ value can be NULL. */
+
ctxt->set_str_option (opt, value);
}
@@ -427,8 +645,9 @@ gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
enum gcc_jit_int_option opt,
int value)
{
- gcc_assert (ctxt);
- ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+ RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+ /* opt is checked by the inner function. */
+
ctxt->set_int_option (opt, value);
}
@@ -437,16 +656,17 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
enum gcc_jit_bool_option opt,
int value)
{
- gcc_assert (ctxt);
- ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+ RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+ /* opt is checked by the inner function. */
+
ctxt->set_bool_option (opt, value);
}
gcc_jit_result *
gcc_jit_context_compile (gcc_jit_context *ctxt)
{
- gcc_assert (ctxt);
- ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+ RETURN_NULL_IF_NOT_INITIAL_CTXT (ctxt);
+
return (gcc_jit_result *)ctxt->compile ();
}
@@ -454,13 +674,16 @@ void *
gcc_jit_result_get_code (gcc_jit_result *result,
const char *fnname)
{
- gcc_assert (result);
- gcc_assert (fnname);
+ RETURN_NULL_IF_FAIL (result, NULL, "NULL result");
+ RETURN_NULL_IF_FAIL (fnname, NULL, "NULL fnname");
+
return result->get_code (fnname);
}
void
gcc_jit_result_release (gcc_jit_result *result)
{
+ RETURN_IF_FAIL (result, NULL, "NULL result");
+
delete result;
}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a3da478..78d3904 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -386,6 +386,10 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
gcc_jit_param **params,
int is_variadic);
+/* Create a label, to be placed later.
+
+ The name can be NULL, or you can give it a meaningful name, which
+ may show up in dumps of the internal representation. */
extern gcc_jit_label *
gcc_jit_function_new_forward_label (gcc_jit_function *func,
const char *name);
@@ -560,7 +564,9 @@ gcc_jit_function_add_conditional (gcc_jit_function *func,
This is roughly equivalent to this C code:
name:
-*/
+
+ The name can be NULL, or you can give it a meaningful name, which
+ may show up in dumps of the internal representation. */
extern gcc_jit_label *
gcc_jit_function_add_label (gcc_jit_function *func,
gcc_jit_location *loc,
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 87cb958..b23c8fc 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,7 @@
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-null-passed-to-api.c: New.
+
2013-10-17 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-struct.c (code_making_callback): Update
diff --git a/gcc/testsuite/jit.dg/test-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-null-passed-to-api.c
new file mode 100644
index 0000000..245fde0
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-null-passed-to-api.c
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Trigger an API error by passing bad data. */
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ NULL, /* error: this must be non-NULL */
+ "hello_world",
+ 0, NULL,
+ 0);
+
+ /* Client code erroneously considers that it succeeded, so returns 0. */
+ return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+ /* Ensure that the bad API usage prevents the API giving a bogus
+ result back. */
+ CHECK_VALUE (result, NULL);
+}
+
--
1.7.11.7
More information about the Gcc-patches
mailing list