[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