mesa: Fix buffer overflow when parsing generic vertex attributes.
[mesa.git] / src / mesa / shader / nvvertparse.c
index d5b08def43ab00b9d89467305d20daefc1affc07..f5e2df267081dbe2cc41cbe4e2c22c1142b9298b 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  6.5.2
  *
- * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * including any use thereof or modifications thereto.
  */
 
-#include "glheader.h"
-#include "context.h"
-#include "hash.h"
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/macros.h"
 #include "nvprogram.h"
 #include "nvvertparse.h"
-#include "program_instruction.h"
+#include "prog_instruction.h"
+#include "prog_print.h"
 #include "program.h"
 
 
@@ -62,8 +61,8 @@ struct parse_state {
    GLboolean isStateProgram;
    GLboolean isPositionInvariant;
    GLboolean isVersion1_1;
-   GLuint inputsRead;
-   GLuint outputsWritten;
+   GLbitfield inputsRead;
+   GLbitfield outputsWritten;
    GLboolean anyProgRegsWritten;
    GLuint numInst;                 /* number of instructions parsed */
 };
@@ -293,18 +292,6 @@ static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
    "PSIZ", "BFC0", "BFC1", NULL
 };
 
-/* NOTE: the order here must match opcodes in program_instruction.h */
-static const char *Opcodes[] = {
-   "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
-   "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
-   "ABS", "END",
-   /* GL_ARB_vertex_program */
-   "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
-   /* Mesa-specific */
-   "PRINT",
-   NULL
-};
-
 
 
 /**
@@ -654,12 +641,12 @@ Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *sr
       RETURN_ERROR;
    if (token[0] == '-') {
       (void) Parse_String(parseState, "-");
-      srcReg->NegateBase = GL_TRUE;
+      srcReg->Negate = NEGATE_XYZW;
       if (!Peek_Token(parseState, token))
          RETURN_ERROR;
    }
    else {
-      srcReg->NegateBase = GL_FALSE;
+      srcReg->Negate = NEGATE_NONE;
    }
 
    /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
@@ -698,19 +685,22 @@ Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *sr
       if (token[1] == 0) {
          /* single letter swizzle */
          if (token[0] == 'x')
-            srcReg->Swizzle = MAKE_SWIZZLE4(0, 0, 0, 0);
+            srcReg->Swizzle = SWIZZLE_XXXX;
          else if (token[0] == 'y')
-            srcReg->Swizzle = MAKE_SWIZZLE4(1, 1, 1, 1);
+            srcReg->Swizzle = SWIZZLE_YYYY;
          else if (token[0] == 'z')
-            srcReg->Swizzle = MAKE_SWIZZLE4(2, 2, 2, 2);
+            srcReg->Swizzle = SWIZZLE_ZZZZ;
          else if (token[0] == 'w')
-            srcReg->Swizzle = MAKE_SWIZZLE4(3, 3, 3, 3);
+            srcReg->Swizzle = SWIZZLE_WWWW;
          else
             RETURN_ERROR1("Expected x, y, z, or w");
       }
       else {
          /* 2, 3 or 4-component swizzle */
          GLint k;
+
+         srcReg->Swizzle = 0;
+
          for (k = 0; token[k] && k < 5; k++) {
             if (token[k] == 'x')
                srcReg->Swizzle |= 0 << (k*3);
@@ -744,13 +734,13 @@ Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *src
    if (!Peek_Token(parseState, token))
       RETURN_ERROR;
    if (token[0] == '-') {
-      srcReg->NegateBase = GL_TRUE;
+      srcReg->Negate = NEGATE_XYZW;
       (void) Parse_String(parseState, "-"); /* consume '-' */
       if (!Peek_Token(parseState, token))
          RETURN_ERROR;
    }
    else {
-      srcReg->NegateBase = GL_FALSE;
+      srcReg->Negate = NEGATE_NONE;
    }
 
    /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
@@ -810,7 +800,6 @@ Parse_UnaryOpInstruction(struct parse_state *parseState,
       RETURN_ERROR1("ABS illegal for vertex program 1.0");
 
    inst->Opcode = opcode;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* dest reg */
    if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
@@ -843,7 +832,6 @@ Parse_BiOpInstruction(struct parse_state *parseState,
       RETURN_ERROR1("SUB illegal for vertex program 1.0");
 
    inst->Opcode = opcode;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* dest reg */
    if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
@@ -891,7 +879,6 @@ Parse_TriOpInstruction(struct parse_state *parseState,
                        enum prog_opcode opcode)
 {
    inst->Opcode = opcode;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* dest reg */
    if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
@@ -962,7 +949,6 @@ Parse_ScalarInstruction(struct parse_state *parseState,
       RETURN_ERROR1("RCC illegal for vertex program 1.0");
 
    inst->Opcode = opcode;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* dest reg */
    if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
@@ -988,7 +974,11 @@ static GLboolean
 Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
 {
    inst->Opcode = OPCODE_ARL;
-   inst->StringPos = parseState->curLine - parseState->start;
+
+   /* Make ARB_vp backends happy */
+   inst->DstReg.File = PROGRAM_ADDRESS;
+   inst->DstReg.WriteMask = WRITEMASK_X;
+   inst->DstReg.Index = 0;
 
    /* dest A0 reg */
    if (!Parse_AddrReg(parseState))
@@ -1016,7 +1006,6 @@ Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *in
    GLubyte token[100];
 
    inst->Opcode = OPCODE_END;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* this should fail! */
    if (Parse_Token(parseState, token))
@@ -1050,7 +1039,6 @@ Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *
    GLint idx;
 
    inst->Opcode = OPCODE_PRINT;
-   inst->StringPos = parseState->curLine - parseState->start;
 
    /* The first argument is a literal string 'just like this' */
    if (!Parse_String(parseState, "'"))
@@ -1060,7 +1048,7 @@ Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *
    for (len = 0; str[len] != '\''; len++) /* find closing quote */
       ;
    parseState->pos += len + 1;
-   msg = _mesa_malloc(len + 1);
+   msg = (GLubyte*) _mesa_malloc(len + 1);
 
    _mesa_memcpy(msg, str, len);
    msg[len] = 0;
@@ -1074,7 +1062,7 @@ Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *
          RETURN_ERROR;
 
       srcReg->RelAddr = GL_FALSE;
-      srcReg->NegateBase = GL_FALSE;
+      srcReg->Negate = NEGATE_NONE;
       srcReg->Swizzle = SWIZZLE_NOOP;
 
       /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
@@ -1147,7 +1135,7 @@ Parse_InstructionSequence(struct parse_state *parseState,
       struct prog_instruction *inst = program + parseState->numInst;
 
       /* Initialize the instruction */
-      _mesa_init_instruction(inst);
+      _mesa_init_instructions(inst, 1);
 
       if (Parse_String(parseState, "MOV")) {
          if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
@@ -1294,7 +1282,7 @@ Parse_Program(struct parse_state *parseState,
 void
 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
                               const GLubyte *str, GLsizei len,
-                              struct vertex_program *program)
+                              struct gl_vertex_program *program)
 {
    struct parse_state parseState;
    struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
@@ -1368,7 +1356,7 @@ _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
       }
       else {
          if (!parseState.isPositionInvariant &&
-             !(parseState.outputsWritten & 1)) {
+             !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
             /* bit 1 = HPOS register */
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "glLoadProgramNV(HPOS not written)");
@@ -1378,35 +1366,36 @@ _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
 
       /* copy the compiled instructions */
       assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
-      newInst = (struct prog_instruction *)
-         MALLOC(parseState.numInst * sizeof(struct prog_instruction));
+      newInst = _mesa_alloc_instructions(parseState.numInst);
       if (!newInst) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
-         FREE(programString);
+         _mesa_free(programString);
          return;  /* out of memory */
       }
-      MEMCPY(newInst, instBuffer,
-             parseState.numInst * sizeof(struct prog_instruction));
+      _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
 
       /* install the program */
       program->Base.Target = target;
       if (program->Base.String) {
-         FREE(program->Base.String);
+         _mesa_free(program->Base.String);
       }
       program->Base.String = programString;
       program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
-      if (program->Instructions) {
-         FREE(program->Instructions);
+      if (program->Base.Instructions) {
+         _mesa_free(program->Base.Instructions);
       }
-      program->Instructions = newInst;
-      program->InputsRead = parseState.inputsRead;
-      program->OutputsWritten = parseState.outputsWritten;
+      program->Base.Instructions = newInst;
+      program->Base.InputsRead = parseState.inputsRead;
+      if (parseState.isPositionInvariant)
+         program->Base.InputsRead |= VERT_BIT_POS;
+      program->Base.NumInstructions = parseState.numInst;
+      program->Base.OutputsWritten = parseState.outputsWritten;
       program->IsPositionInvariant = parseState.isPositionInvariant;
       program->IsNVProgram = GL_TRUE;
 
 #ifdef DEBUG_foo
       _mesa_printf("--- glLoadProgramNV result ---\n");
-      _mesa_print_nv_vertex_program(program);
+      _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
       _mesa_printf("------------------------------\n");
 #endif
    }
@@ -1422,172 +1411,6 @@ _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
 }
 
 
-static void
-PrintSrcReg(const struct prog_src_register *src)
-{
-   static const char comps[5] = "xyzw";
-   if (src->NegateBase)
-      _mesa_printf("-");
-   if (src->RelAddr) {
-      if (src->Index > 0)
-         _mesa_printf("c[A0.x + %d]", src->Index);
-      else if (src->Index < 0)
-         _mesa_printf("c[A0.x - %d]", -src->Index);
-      else
-         _mesa_printf("c[A0.x]");
-   }
-   else if (src->File == PROGRAM_OUTPUT) {
-      _mesa_printf("o[%s]", OutputRegisters[src->Index]);
-   }
-   else if (src->File == PROGRAM_INPUT) {
-      _mesa_printf("v[%s]", InputRegisters[src->Index]);
-   }
-   else if (src->File == PROGRAM_ENV_PARAM) {
-      _mesa_printf("c[%d]", src->Index);
-   }
-   else {
-      ASSERT(src->File == PROGRAM_TEMPORARY);
-      _mesa_printf("R%d", src->Index);
-   }
-
-   if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
-       GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
-       GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
-      _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
-   }
-   else if (src->Swizzle != SWIZZLE_NOOP) {
-      _mesa_printf(".%c%c%c%c",
-             comps[GET_SWZ(src->Swizzle, 0)],
-             comps[GET_SWZ(src->Swizzle, 1)],
-             comps[GET_SWZ(src->Swizzle, 2)],
-             comps[GET_SWZ(src->Swizzle, 3)]);
-   }
-}
-
-
-static void
-PrintDstReg(const struct prog_dst_register *dst)
-{
-   if (dst->File == PROGRAM_OUTPUT) {
-      _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
-   }
-   else if (dst->File == PROGRAM_INPUT) {
-      _mesa_printf("v[%s]", InputRegisters[dst->Index]);
-   }
-   else if (dst->File == PROGRAM_ENV_PARAM) {
-      _mesa_printf("c[%d]", dst->Index);
-   }
-   else {
-      ASSERT(dst->File == PROGRAM_TEMPORARY);
-      _mesa_printf("R%d", dst->Index);
-   }
-
-   if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
-      _mesa_printf(".");
-      if (dst->WriteMask & WRITEMASK_X)
-         _mesa_printf("x");
-      if (dst->WriteMask & WRITEMASK_Y)
-         _mesa_printf("y");
-      if (dst->WriteMask & WRITEMASK_Z)
-         _mesa_printf("z");
-      if (dst->WriteMask & WRITEMASK_W)
-         _mesa_printf("w");
-   }
-}
-
-
-/**
- * Print a single NVIDIA vertex program instruction.
- */
-void
-_mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
-{
-   switch (inst->Opcode) {
-      case OPCODE_MOV:
-      case OPCODE_LIT:
-      case OPCODE_RCP:
-      case OPCODE_RSQ:
-      case OPCODE_EXP:
-      case OPCODE_LOG:
-      case OPCODE_RCC:
-      case OPCODE_ABS:
-         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
-         PrintDstReg(&inst->DstReg);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[0]);
-         _mesa_printf(";\n");
-         break;
-      case OPCODE_MUL:
-      case OPCODE_ADD:
-      case OPCODE_DP3:
-      case OPCODE_DP4:
-      case OPCODE_DST:
-      case OPCODE_MIN:
-      case OPCODE_MAX:
-      case OPCODE_SLT:
-      case OPCODE_SGE:
-      case OPCODE_DPH:
-      case OPCODE_SUB:
-         _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
-         PrintDstReg(&inst->DstReg);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[0]);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[1]);
-         _mesa_printf(";\n");
-         break;
-      case OPCODE_MAD:
-         _mesa_printf("MAD ");
-         PrintDstReg(&inst->DstReg);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[0]);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[1]);
-         _mesa_printf(", ");
-         PrintSrcReg(&inst->SrcReg[2]);
-         _mesa_printf(";\n");
-         break;
-      case OPCODE_ARL:
-         _mesa_printf("ARL A0.x, ");
-         PrintSrcReg(&inst->SrcReg[0]);
-         _mesa_printf(";\n");
-         break;
-      case OPCODE_PRINT:
-         _mesa_printf("PRINT '%s'", inst->Data);
-         if (inst->SrcReg[0].File) {
-            _mesa_printf(", ");
-            PrintSrcReg(&inst->SrcReg[0]);
-            _mesa_printf(";\n");
-         }
-         else {
-            _mesa_printf("\n");
-         }
-         break;
-      case OPCODE_END:
-         _mesa_printf("END\n");
-         break;
-      default:
-         _mesa_printf("BAD INSTRUCTION\n");
-   }
-}
-
-
-/**
- * Print (unparse) the given vertex program.  Just for debugging.
- */
-void
-_mesa_print_nv_vertex_program(const struct vertex_program *program)
-{
-   const struct prog_instruction *inst;
-
-   for (inst = program->Instructions; ; inst++) {
-      _mesa_print_nv_vertex_instruction(inst);
-      if (inst->Opcode == OPCODE_END)
-         return;
-   }
-}
-
-
 const char *
 _mesa_nv_vertex_input_register_name(GLuint i)
 {
@@ -1603,26 +1426,3 @@ _mesa_nv_vertex_output_register_name(GLuint i)
    return OutputRegisters[i];
 }
 
-
-/**
- * Initialize program instruction fields to defaults.
- */
-void
-_mesa_init_instruction(struct prog_instruction *inst)
-{
-   _mesa_bzero(inst, sizeof(struct prog_instruction));
-
-   inst->SrcReg[0].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
-   inst->SrcReg[1].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
-   inst->SrcReg[2].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
-
-   inst->DstReg.File = PROGRAM_UNDEFINED;
-   inst->DstReg.WriteMask = WRITEMASK_XYZW;
-   inst->DstReg.CondMask = COND_TR;
-   inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
-   
-   inst->Precision = FLOAT32;
-}