<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Aug 17, 2017 at 10:29 AM, Erik Faye-Lund <span dir="ltr"><<a href="mailto:kusmabite@gmail.com" target="_blank">kusmabite@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Aug 17, 2017 at 7:22 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
> These helpers are much nicer than just using assert because they don't<br>
> kill your process.  Instead, it longjmps back to spirv_to_nir(), cleans<br>
> up all the temporary memory, and nicely returns NULL.  While crashing is<br>
> completely OK in the Vulkan world, it's not considered to be quite so<br>
> nice in GL.  This should help us to make SPIR-V parsing much more<br>
> robust.  The one downside here is that vtn_assert is not compiled out in<br>
> release builds like assert() is so it isn't free.<br>
> ---<br>
>  src/compiler/spirv/spirv_to_<wbr>nir.c | 20 ++++++++++++++++++++<br>
>  src/compiler/spirv/vtn_<wbr>private.h  | 31 ++++++++++++++++++++++++++++++<wbr>+<br>
>  2 files changed, 51 insertions(+)<br>
><br>
> diff --git a/src/compiler/spirv/spirv_to_<wbr>nir.c b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
> index e59f2b2..af542e8 100644<br>
> --- a/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
> +++ b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
> @@ -104,6 +104,20 @@ _vtn_warn(struct vtn_builder *b, const char *file, unsigned line,<br>
>     va_end(args);<br>
>  }<br>
><br>
> +void<br>
> +_vtn_fail(struct vtn_builder *b, const char *file, unsigned line,<br>
> +          const char *fmt, ...)<br>
> +{<br>
> +   va_list args;<br>
> +<br>
> +   va_start(args, fmt);<br>
> +   vtn_log_err(b, NIR_SPIRV_DEBUG_LEVEL_ERROR, "SPIR-V parsing FAILED:\n",<br>
> +               file, line, fmt, args);<br>
> +   va_end(args);<br>
> +<br>
> +   longjmp(b->fail_jump, 1);<br>
> +}<br>
> +<br>
>  struct spec_constant_value {<br>
>     bool is_double;<br>
>     union {<br>
> @@ -3420,6 +3434,12 @@ spirv_to_nir(const uint32_t *words, size_t word_count,<br>
>     b->entry_point_name = entry_point_name;<br>
>     b->ext = ext;<br>
><br>
> +   /* See also _vtn_fail() */<br>
> +   if (setjmp(b->fail_jump)) {<br>
> +      ralloc_free(b);<br>
> +      return NULL;<br>
> +   }<br>
> +<br>
>     const uint32_t *word_end = words + word_count;<br>
><br>
>     /* Handle the SPIR-V header (first 4 dwords)  */<br>
> diff --git a/src/compiler/spirv/vtn_<wbr>private.h b/src/compiler/spirv/vtn_<wbr>private.h<br>
> index 3eb601d..f640289 100644<br>
> --- a/src/compiler/spirv/vtn_<wbr>private.h<br>
> +++ b/src/compiler/spirv/vtn_<wbr>private.h<br>
> @@ -28,6 +28,8 @@<br>
>  #ifndef _VTN_PRIVATE_H_<br>
>  #define _VTN_PRIVATE_H_<br>
><br>
> +#include <setjmp.h><br>
> +<br>
>  #include "nir/nir.h"<br>
>  #include "nir/nir_builder.h"<br>
>  #include "util/u_dynarray.h"<br>
> @@ -49,6 +51,32 @@ void _vtn_warn(struct vtn_builder *b, const char *file, unsigned line,<br>
>                 const char *fmt, ...) PRINTFLIKE(4, 5);<br>
>  #define vtn_warn(...) _vtn_warn(b, __FILE__, __LINE__, __VA_ARGS__)<br>
><br>
> +/** Fail SPIR-V parsing<br>
> + *<br>
> + * This function logs an error and then bails out of the shader compile using<br>
> + * longjmp.  This being safe relies on two things:<br>
> + *<br>
> + *  1) We must guarantee that setjmp is called after allocating the builder<br>
> + *     and setting up b->debug (so that logging works) but before before any<br>
> + *     errors have a chance to occur.<br>
> + *<br>
> + *  2) While doing the SPIR-V -> NIR conversion, we need to be careful to<br>
> + *     ensure that all heap allocations happen through ralloc and are parented<br>
> + *     to the builder.<br>
> + *<br>
> + * So long as these two things continue to hold, we can easily longjmp back to<br>
> + * spirv_to_nir(), clean up the builder, and return NULL.<br>
> + */<br>
<br>
</div></div>Technically speaking, there's probably some more requirements, but<br>
they might not be relevant here, for instance that no failures can<br>
happen while mutex locks are being held.<br></blockquote><div> </div></div></div><div class="gmail_extra">Right.  That wouldn't be bad to state.  Fortunately, all uses of mutexes from within spirv_to_nir are encapsulated in glsl_type functions so we have no way to get back into spirv_to_nir code while a mutex is held.  I'll add that one to the list.</div><div class="gmail_extra"><br></div><div class="gmail_extra">--Jason<br></div></div>