From: Ian Romanick <[email protected]>

The #version directive can only handle decimal constants.  Enforce that
the value is a decimal constant.

Section 3.3 (Preprocessor) of the GLSL 4.50 spec says:

    The language version a shader is written to is specified by

        #version number profile opt

    where number must be a version of the language, following the same
    convention as __VERSION__ above.

The same section also says:

    __VERSION__ will substitute a decimal integer reflecting the version
    number of the OpenGL shading language.

Use a separate flag to track whether or not the #version line has been
encountered.  Any possible sentinel (0 is currently used) could be
specified in a #version directive.  This would lead to trying to
(internally) redefine __VERSION__.  Since there is no parser location
for this addition, NULL is passed.  This eventually results in a NULL
dereference and a segfault.

Attempts to use -1 as the sentinel would also fail if '#version
4294967295' or '#version 18446744073709551615' were used.  We should
have piglit tests for both of these.

Signed-off-by: Ian Romanick <[email protected]>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97420
Cc: [email protected]
Cc: Juan A. Suarez Romero <[email protected]>
Cc: Karol Herbst <[email protected]>
---
 src/compiler/glsl/glcpp/glcpp-parse.y | 25 +++++++++++++++++++------
 src/compiler/glsl/glcpp/glcpp.h       |  9 +++++++++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y 
b/src/compiler/glsl/glcpp/glcpp-parse.y
index b80ff04..63012bc 100644
--- a/src/compiler/glsl/glcpp/glcpp-parse.y
+++ b/src/compiler/glsl/glcpp/glcpp-parse.y
@@ -177,7 +177,7 @@ add_builtin_define(glcpp_parser_t *parser, const char 
*name, int value);
          * (such as the <HASH> and <DEFINE> start conditions in the lexer). */
 %token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER 
OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF 
VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING 
LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS
 %token PASTE
-%type <ival> INTEGER operator SPACE integer_constant
+%type <ival> INTEGER operator SPACE integer_constant version_constant
 %type <expression_value> expression
 %type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER 
ERROR_TOKEN PRAGMA
 %type <string_list> identifier_list
@@ -419,14 +419,14 @@ control_line_success:
 |      HASH_TOKEN ENDIF {
                _glcpp_parser_skip_stack_pop (parser, & @1);
        } NEWLINE
-|      HASH_TOKEN VERSION_TOKEN integer_constant NEWLINE {
-               if (parser->version != 0) {
+|      HASH_TOKEN VERSION_TOKEN version_constant NEWLINE {
+               if (parser->version_set) {
                        glcpp_error(& @1, parser, "#version must appear on the 
first line");
                }
                _glcpp_parser_handle_version_declaration(parser, $3, NULL, 
true);
        }
-|      HASH_TOKEN VERSION_TOKEN integer_constant IDENTIFIER NEWLINE {
-               if (parser->version != 0) {
+|      HASH_TOKEN VERSION_TOKEN version_constant IDENTIFIER NEWLINE {
+               if (parser->version_set) {
                        glcpp_error(& @1, parser, "#version must appear on the 
first line");
                }
                _glcpp_parser_handle_version_declaration(parser, $3, $4, true);
@@ -465,6 +465,17 @@ integer_constant:
                $$ = $1;
        }
 
+version_constant:
+       INTEGER_STRING {
+          /* Both octal and hexadecimal constants begin with 0. */
+          if ($1[0] == '0' && $1[1] != '\0') {
+               glcpp_error(&@1, parser, "invalid #version \"%s\" (not a 
decimal constant)", $1);
+               $$ = 0;
+          } else {
+               $$ = strtoll($1, NULL, 10);
+          }
+       }
+
 expression:
        integer_constant {
                $$.value = $1;
@@ -1361,6 +1372,7 @@ glcpp_parser_create(glcpp_extension_iterator extensions, 
void *state, gl_api api
    parser->state = state;
    parser->api = api;
    parser->version = 0;
+   parser->version_set = false;
 
    parser->has_new_line_number = 0;
    parser->new_line_number = 1;
@@ -2293,10 +2305,11 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t 
*parser, intmax_t versio
                                          const char *es_identifier,
                                          bool explicitly_set)
 {
-   if (parser->version != 0)
+   if (parser->version_set)
       return;
 
    parser->version = version;
+   parser->version_set = true;
 
    add_builtin_define (parser, "__VERSION__", version);
 
diff --git a/src/compiler/glsl/glcpp/glcpp.h b/src/compiler/glsl/glcpp/glcpp.h
index bb4ad67..232e053 100644
--- a/src/compiler/glsl/glcpp/glcpp.h
+++ b/src/compiler/glsl/glcpp/glcpp.h
@@ -208,6 +208,15 @@ struct glcpp_parser {
        void *state;
        gl_api api;
        unsigned version;
+
+       /**
+        * Has the #version been set?
+        *
+        * A separate flag is used because any possible sentinel value in
+        * \c ::version could also be set by a #version line.
+        */
+       bool version_set;
+
        bool has_new_line_number;
        int new_line_number;
        bool has_new_source_number;
-- 
2.5.5

_______________________________________________
mesa-dev mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to