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 <dmalc...@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 <dmalc...@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 <dmalc...@redhat.com> + + * jit.dg/test-null-passed-to-api.c: New. + 2013-10-17 David Malcolm <dmalc...@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