On Thu, Aug 17, 2017 at 7:22 PM, Jason Ekstrand <ja...@jlekstrand.net> wrote:
> These helpers are much nicer than just using assert because they don't
> kill your process.  Instead, it longjmps back to spirv_to_nir(), cleans
> up all the temporary memory, and nicely returns NULL.  While crashing is
> completely OK in the Vulkan world, it's not considered to be quite so
> nice in GL.  This should help us to make SPIR-V parsing much more
> robust.  The one downside here is that vtn_assert is not compiled out in
> release builds like assert() is so it isn't free.
> ---
>  src/compiler/spirv/spirv_to_nir.c | 20 ++++++++++++++++++++
>  src/compiler/spirv/vtn_private.h  | 31 +++++++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+)
>
> diff --git a/src/compiler/spirv/spirv_to_nir.c 
> b/src/compiler/spirv/spirv_to_nir.c
> index e59f2b2..af542e8 100644
> --- a/src/compiler/spirv/spirv_to_nir.c
> +++ b/src/compiler/spirv/spirv_to_nir.c
> @@ -104,6 +104,20 @@ _vtn_warn(struct vtn_builder *b, const char *file, 
> unsigned line,
>     va_end(args);
>  }
>
> +void
> +_vtn_fail(struct vtn_builder *b, const char *file, unsigned line,
> +          const char *fmt, ...)
> +{
> +   va_list args;
> +
> +   va_start(args, fmt);
> +   vtn_log_err(b, NIR_SPIRV_DEBUG_LEVEL_ERROR, "SPIR-V parsing FAILED:\n",
> +               file, line, fmt, args);
> +   va_end(args);
> +
> +   longjmp(b->fail_jump, 1);
> +}
> +
>  struct spec_constant_value {
>     bool is_double;
>     union {
> @@ -3420,6 +3434,12 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
>     b->entry_point_name = entry_point_name;
>     b->ext = ext;
>
> +   /* See also _vtn_fail() */
> +   if (setjmp(b->fail_jump)) {
> +      ralloc_free(b);
> +      return NULL;
> +   }
> +
>     const uint32_t *word_end = words + word_count;
>
>     /* Handle the SPIR-V header (first 4 dwords)  */
> diff --git a/src/compiler/spirv/vtn_private.h 
> b/src/compiler/spirv/vtn_private.h
> index 3eb601d..f640289 100644
> --- a/src/compiler/spirv/vtn_private.h
> +++ b/src/compiler/spirv/vtn_private.h
> @@ -28,6 +28,8 @@
>  #ifndef _VTN_PRIVATE_H_
>  #define _VTN_PRIVATE_H_
>
> +#include <setjmp.h>
> +
>  #include "nir/nir.h"
>  #include "nir/nir_builder.h"
>  #include "util/u_dynarray.h"
> @@ -49,6 +51,32 @@ void _vtn_warn(struct vtn_builder *b, const char *file, 
> unsigned line,
>                 const char *fmt, ...) PRINTFLIKE(4, 5);
>  #define vtn_warn(...) _vtn_warn(b, __FILE__, __LINE__, __VA_ARGS__)
>
> +/** Fail SPIR-V parsing
> + *
> + * This function logs an error and then bails out of the shader compile using
> + * longjmp.  This being safe relies on two things:
> + *
> + *  1) We must guarantee that setjmp is called after allocating the builder
> + *     and setting up b->debug (so that logging works) but before before any
> + *     errors have a chance to occur.
> + *
> + *  2) While doing the SPIR-V -> NIR conversion, we need to be careful to
> + *     ensure that all heap allocations happen through ralloc and are 
> parented
> + *     to the builder.
> + *
> + * So long as these two things continue to hold, we can easily longjmp back 
> to
> + * spirv_to_nir(), clean up the builder, and return NULL.
> + */

Technically speaking, there's probably some more requirements, but
they might not be relevant here, for instance that no failures can
happen while mutex locks are being held.
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to