[Mesa-dev] [PATCH] mesa: Move transform feedback error check to reduce array overflow risk.

Ian Romanick idr at freedesktop.org
Mon Jan 9 13:00:20 PST 2012


On 01/09/2012 12:02 PM, Paul Berry wrote:
> Previous to this patch, we didn't do the limit check for
> MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS until the end of the
> store_tfeedback_info() function, *after* storing all of the transform
> feedback info in the gl_transform_feedback_info::Outputs array.  This
> meant that the limit check wouldn't prevent us from overflowing the
> array and corrupting memory.
>
> This patch moves the limit check to the top of tfeedback_decl::store()
> so that there is no risk of overflowing the array.  It also adds
> assertions to verify that the checks for
> MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS and
> MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS are sufficient to avoid
> array overflow.
>
> Note: strictly speaking this patch isn't necessary, since the maximum
> possible number of varyings is MAX_VARYING (16), whereas the size of
> the Outputs array is MAX_PROGRAM_OUTPUTS (64), so it's impossible to
> have enough varyings to overflow the array.  However it seems prudent

Why is Outputs so large?

> to do the limit check before the array access in case these limits
> change in the future.
> ---
>   src/glsl/linker.cpp |   52 +++++++++++++++++++++++++++++++-------------------
>   1 files changed, 32 insertions(+), 20 deletions(-)
>
> diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
> index 39a9c46..0d85aee 100644
> --- a/src/glsl/linker.cpp
> +++ b/src/glsl/linker.cpp
> @@ -1388,7 +1388,7 @@ public:
>      static bool is_same(const tfeedback_decl&x, const tfeedback_decl&y);
>      bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog,
>                           ir_variable *output_var);
> -   bool store(struct gl_shader_program *prog,
> +   bool store(struct gl_context *ctx, struct gl_shader_program *prog,
>                 struct gl_transform_feedback_info *info, unsigned buffer,
>   	      unsigned varying) const;
>
> @@ -1631,7 +1631,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
>    * is returned.
>    */
>   bool
> -tfeedback_decl::store(struct gl_shader_program *prog,
> +tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
>                         struct gl_transform_feedback_info *info,
>                         unsigned buffer, unsigned varying) const
>   {
> @@ -1647,6 +1647,35 @@ tfeedback_decl::store(struct gl_shader_program *prog,
>                      this->orig_name);
>         return false;
>      }
> +
> +   /* From GL_EXT_transform_feedback:
> +    *   A program will fail to link if:
> +    *
> +    *     * the total number of components to capture is greater than
> +    *       the constant MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT
> +    *       and the buffer mode is INTERLEAVED_ATTRIBS_EXT.
> +    */
> +   if (prog->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS&&
> +       info->BufferStride[buffer] + this->num_components()>
> +       ctx->Const.MaxTransformFeedbackInterleavedComponents) {
> +      linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
> +                   "limit has been exceeded.");
> +      return false;
> +   }
> +
> +   /* Verify that the checks on MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
> +    * and MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS are sufficient to prevent
> +    * overflow of info->Outputs[].  In worst case we generate one entry in
> +    * Outputs[] per component so a conservative check is to verify that the
> +    * size of the array is greater than or equal to both
> +    * MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS and
> +    * MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS.
> +    */
> +   assert(Elements(info->Outputs)>=
> +          ctx->Const.MaxTransformFeedbackInterleavedComponents);
> +   assert(Elements(info->Outputs)>=
> +          ctx->Const.MaxTransformFeedbackSeparateComponents);
> +
>      unsigned translated_size = this->size;
>      if (this->is_clip_distance_mesa)
>         translated_size = (translated_size + 3) / 4;
> @@ -1943,7 +1972,6 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
>                        unsigned num_tfeedback_decls,
>                        tfeedback_decl *tfeedback_decls)
>   {
> -   unsigned total_tfeedback_components = 0;
>      bool separate_attribs_mode =
>         prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS;
>
> @@ -1962,25 +1990,9 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
>
>      for (unsigned i = 0; i<  num_tfeedback_decls; ++i) {
>         unsigned buffer = separate_attribs_mode ? i : 0;
> -      if (!tfeedback_decls[i].store(prog,&prog->LinkedTransformFeedback,
> +      if (!tfeedback_decls[i].store(ctx, prog,&prog->LinkedTransformFeedback,
>                                       buffer, i))
>            return false;
> -      total_tfeedback_components += tfeedback_decls[i].num_components();
> -   }
> -
> -   /* From GL_EXT_transform_feedback:
> -    *   A program will fail to link if:
> -    *
> -    *     * the total number of components to capture is greater than
> -    *       the constant MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT
> -    *       and the buffer mode is INTERLEAVED_ATTRIBS_EXT.
> -    */
> -   if (prog->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS&&
> -       total_tfeedback_components>
> -       ctx->Const.MaxTransformFeedbackInterleavedComponents) {
> -      linker_error(prog, "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
> -                   "limit has been exceeded.");
> -      return false;
>      }
>
>      return true;



More information about the mesa-dev mailing list