PR jit/95296 reports an ICE when using libgccjit to create a local of void type.
This patch adds checking to various API entrypoints in libgccjit.c so that they fail gracefully with an error if the client code attempts to create various kinds of rvalues or types involving void types. The patch documents these and various pre-existing restrictions on types in the API. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to master as r11-636-g6f7585deedc140667fd496b48c9fc4f7d625605c. gcc/jit/ChangeLog: PR jit/95296 * docs/topics/expressions.rst (Unary Operations): Document that result_type of gcc_jit_context_new_unary_op must be a numeric type. (Binary Operations): Likewise for gcc_jit_context_new_binary_op. (Global variables): Document that "type" of gcc_jit_context_new_global must be non-`void`. * docs/topics/function-pointers.rst (gcc_jit_context_new_function_ptr_type): Document that the param_types must be non-void, but that return_type may be. * docs/topics/functions.rst (Params): Document that gcc_jit_context_new_param's type must be non-void. (Functions): Likewise for gcc_jit_function_new_local. * docs/topics/types.rst (gcc_jit_context_new_array_type): Document that the type must be non-void. (gcc_jit_context_new_field): Likewise. * docs/_build/texinfo/Makefile: Regenerate. * docs/_build/texinfo/libgccjit.texi: Regenerate. * libgccjit.c (gcc_jit_context_new_array_type): Fail if element_type is void. (gcc_jit_context_new_field): Likewise for "type". (gcc_jit_context_new_function_ptr_type): Likewise for each element of param_types. (gcc_jit_context_new_param): Likewise for "type". (gcc_jit_context_new_global): Likewise. (gcc_jit_function_new_local): Likewise. (gcc_jit_type_get_aligned): Likewise. gcc/testsuite/ChangeLog: PR jit/95296 * jit.dg/test-error-gcc_jit_context_new_global-void-type.c: New test. * jit.dg/test-error-gcc_jit_function_new_local-void-type.c: New test. * jit.dg/test-fuzzer.c (fuzzer_init): Allow for make_random_type to return NULL. (get_random_type): Allow for elements in f->types to be NULL. --- gcc/jit/docs/topics/expressions.rst | 6 ++++ gcc/jit/docs/topics/function-pointers.rst | 2 ++ gcc/jit/docs/topics/functions.rst | 4 +++ gcc/jit/docs/topics/types.rst | 6 ++-- gcc/jit/libgccjit.c | 34 ++++++++++++++++--- ...ror-gcc_jit_context_new_global-void-type.c | 25 ++++++++++++++ ...ror-gcc_jit_function_new_local-void-type.c | 27 +++++++++++++++ gcc/testsuite/jit.dg/test-fuzzer.c | 2 -- 8 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_context_new_global-void-type.c create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_function_new_local-void-type.c diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index db2f2ca2e9c..d783ceea51a 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -162,6 +162,8 @@ Unary Operations Build a unary operation out of an input rvalue. + The parameter ``result_type`` must be a numeric type. + .. type:: enum gcc_jit_unary_op The available unary operations are: @@ -227,6 +229,8 @@ Binary Operations Build a binary operation out of two constituent rvalues. + The parameter ``result_type`` must be a numeric type. + .. type:: enum gcc_jit_binary_op The available binary operations are: @@ -547,6 +551,8 @@ Global variables Add a new global variable of the given type and name to the context. + The parameter ``type`` must be non-`void`. + The parameter ``name`` must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer. diff --git a/gcc/jit/docs/topics/function-pointers.rst b/gcc/jit/docs/topics/function-pointers.rst index c8424ee17dc..7d2fa8b278d 100644 --- a/gcc/jit/docs/topics/function-pointers.rst +++ b/gcc/jit/docs/topics/function-pointers.rst @@ -78,3 +78,5 @@ Here's an example of creating a function pointer type corresponding to C's Generate a :c:type:`gcc_jit_type` for a function pointer with the given return type and parameters. + + Each of `param_types` must be non-`void`; `return_type` may be `void`. diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst index 74d479af1bb..29ce96c1e56 100644 --- a/gcc/jit/docs/topics/functions.rst +++ b/gcc/jit/docs/topics/functions.rst @@ -35,6 +35,8 @@ Params In preparation for creating a function, create a new parameter of the given type and name. + The parameter ``type`` must be non-`void`. + The parameter ``name`` must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer. @@ -148,6 +150,8 @@ Functions Create a new local variable within the function, of the given type and name. + The parameter ``type`` must be non-`void`. + The parameter ``name`` must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer. diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index d1a39eeaf3b..ea7c8ff4542 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -115,13 +115,13 @@ Pointers, `const`, and `volatile` gcc_jit_type *element_type, \ int num_elements) - Given type "T", get type "T[N]" (for a constant N). + Given non-`void` type "T", get type "T[N]" (for a constant N). .. function:: gcc_jit_type *\ gcc_jit_type_get_aligned (gcc_jit_type *type, \ size_t alignment_in_bytes) - Given type "T", get type: + Given non-`void` type "T", get type: .. code-block:: c @@ -243,6 +243,8 @@ You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and Construct a new field, with the given type and name. + The parameter ``type`` must be non-`void`. + The parameter ``name`` must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer. diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index a29e9885e59..3d04f6db3af 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -527,6 +527,8 @@ gcc_jit_context_new_array_type (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (element_type, ctxt, loc, "NULL type"); RETURN_NULL_IF_FAIL (num_elements >= 0, ctxt, NULL, "negative size"); + RETURN_NULL_IF_FAIL (!element_type->is_void (), ctxt, loc, + "void type for elements"); return (gcc_jit_type *)ctxt->new_array_type (loc, element_type, @@ -556,6 +558,11 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt, "unknown size for field \"%s\" (type: %s)", name, type->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF1 ( + !type->is_void (), + ctxt, loc, + "void type for field \"%s\"", + name); return (gcc_jit_field *)ctxt->new_field (loc, type, name); } @@ -786,10 +793,15 @@ gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt, ctxt, loc, "NULL param_types creating function pointer type"); for (int i = 0; i < num_params; i++) - RETURN_NULL_IF_FAIL_PRINTF1 ( - param_types[i], - ctxt, loc, - "NULL parameter type %i creating function pointer type", i); + { + RETURN_NULL_IF_FAIL_PRINTF1 (param_types[i], + ctxt, loc, + "NULL parameter type %i" + " creating function pointer type", i); + RETURN_NULL_IF_FAIL_PRINTF1 (!param_types[i]->is_void (), + ctxt, loc, + "void type for param %i", i); + } return (gcc_jit_type*) ctxt->new_function_ptr_type (loc, return_type, @@ -816,6 +828,9 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name"); + RETURN_NULL_IF_FAIL_PRINTF1 (!type->is_void (), + ctxt, loc, + "void type for param \"%s\"", name); return (gcc_jit_param *)ctxt->new_param (loc, type, name); } @@ -1093,6 +1108,11 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, "unknown size for global \"%s\" (type: %s)", name, type->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF1 ( + !type->is_void (), + ctxt, loc, + "void type for global \"%s\"", + name); return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name); } @@ -1911,6 +1931,11 @@ gcc_jit_function_new_local (gcc_jit_function *func, "unknown size for local \"%s\" (type: %s)", name, type->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF1 ( + !type->is_void (), + ctxt, loc, + "void type for local \"%s\"", + name); return (gcc_jit_lvalue *)func->new_local (loc, type, name); } @@ -3068,6 +3093,7 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, (pow2_or_zerop (alignment_in_bytes), ctxt, NULL, "alignment not a power of two: %zi", alignment_in_bytes); + RETURN_NULL_IF_FAIL (!type->is_void (), ctxt, NULL, "void type"); return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); } diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_context_new_global-void-type.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_context_new_global-void-type.c new file mode 100644 index 00000000000..c310da6a885 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_context_new_global-void-type.c @@ -0,0 +1,25 @@ +#include <libgccjit.h> + +#include "harness.h" + +/* Try to create a "void" global; the API ought to complain. */ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_type *void_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_context_new_global (ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, + void_type, "i"); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_global:" + " void type for global \"i\""); +} diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_function_new_local-void-type.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_function_new_local-void-type.c new file mode 100644 index 00000000000..254abc0c146 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_function_new_local-void-type.c @@ -0,0 +1,27 @@ +#include <libgccjit.h> + +#include "harness.h" + +/* Try to create a "void" local; the API ought to complain. */ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_type *void_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_function *func + = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, + void_type, "test_fn", 0, NULL, 0); + gcc_jit_function_new_local(func, NULL, void_type, "i"); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_function_new_local:" + " void type for local \"i\""); +} diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c index 6943d3ed232..4fd49dacf6d 100644 --- a/gcc/testsuite/jit.dg/test-fuzzer.c +++ b/gcc/testsuite/jit.dg/test-fuzzer.c @@ -96,7 +96,6 @@ fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed) for (i = 0; i < num_types; i++) { gcc_jit_type *type = make_random_type (f); - assert (type); f->types[f->num_types++] = type; } @@ -188,7 +187,6 @@ get_random_type (fuzzer *f) if (i < NUM_TYPES) return gcc_jit_context_get_type (f->ctxt, types[i]); assert ((i - NUM_TYPES) < f->num_types); - assert (f->types[i - NUM_TYPES]); return f->types[i - NUM_TYPES]; } -- 2.21.0