Browse Source

fix: Fixed all OOB accesses in VertexProgram and PixelProgram (#18567)

Milan Burda 5 years ago
parent
commit
87c0b54788

+ 2 - 0
patches/common/swiftshader/.patches

@@ -1 +1,3 @@
 prevent_gldeletequeries_from_deleting_a_live_query.patch
+fix_undefined_behavior_in_offset.patch
+fixed_all_oob_accesses_in_vertexprogram_and_pixelprogram.patch

+ 36 - 0
patches/common/swiftshader/fix_undefined_behavior_in_offset.patch

@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Nicolas Capens <[email protected]>
+Date: Thu, 22 Nov 2018 10:32:35 -0500
+Subject: Fix undefined behavior in OFFSET().
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Accessing members of a null pointer is undefined behavior, even when
+only used to obtain the address again. So use a non-zero value as the
+base pointer address instead. 32 was chosen to provide sufficient
+alignment guarantees.
+
+Bug b/119823623
+
+Change-Id: Ia6d24dd6c2740261948860c45eb35cc489a3a827
+Reviewed-on: https://swiftshader-review.googlesource.com/c/22788
+Tested-by: Nicolas Capens <[email protected]>
+Reviewed-by: Alexis Hétu <[email protected]>
+
+diff --git a/src/Common/Types.hpp b/src/Common/Types.hpp
+index cd08ed5704caa7f6454a619fd4ccbb9e2ddcee2c..837df461ab0676d94e6ee1276d75d289f06851ef 100644
+--- a/src/Common/Types.hpp
++++ b/src/Common/Types.hpp
+@@ -151,7 +151,10 @@ namespace sw
+ 		return v;
+ 	}
+ 
+-	#define OFFSET(s,m) (int)(size_t)&reinterpret_cast<const volatile char&>((((s*)0)->m))
++	// The OFFSET macro is a generalization of the offsetof() macro defined in <cstddef>.
++	// It allows e.g. getting the offset of array elements, even when indexed dynamically.
++	// We cast the address '32' and subtract it again, because null-dereference is undefined behavior.
++	#define OFFSET(s,m) ((int)(size_t)&reinterpret_cast<const volatile char&>((((s*)32)->m)) - 32)
+ }
+ 
+ #endif   // sw_Types_hpp

+ 508 - 0
patches/common/swiftshader/fixed_all_oob_accesses_in_vertexprogram_and_pixelprogram.patch

@@ -0,0 +1,508 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alexis Hetu <[email protected]>
+Date: Thu, 10 Jan 2019 14:04:26 -0500
+Subject: Fixed all OOB accesses in VertexProgram and PixelProgram
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A lot of arrays in VertexProgram and PixelProgram have fixed sizes,
+so programs that have more nested loops or ifs or deeper call stacks
+can cause OOB accesses, which causes security issues in Chromium.
+
+Index clamping was added to prevent any OOB memory accesses here.
+
+This could eventually be fixed properly by first verifying these sizes
+and giving shader compile errors when these limits are exceeded.
+
+Bug chromium:915197 chromium:915206 chromium:915218 b/116373662
+
+Change-Id: I2d0710ed0ce6585f139cba49d5b5d8c909ae6391
+Reviewed-on: https://swiftshader-review.googlesource.com/c/23568
+Tested-by: Alexis Hétu <[email protected]>
+Reviewed-by: Corentin Wallez <[email protected]>
+
+diff --git a/src/Common/Types.hpp b/src/Common/Types.hpp
+index 837df461ab0676d94e6ee1276d75d289f06851ef..fac6d362891cf0b2a19f8faee0a1dbbdddbc3a88 100644
+--- a/src/Common/Types.hpp
++++ b/src/Common/Types.hpp
+@@ -15,6 +15,7 @@
+ #ifndef sw_Types_hpp
+ #define sw_Types_hpp
+ 
++#include <assert.h>
+ #include <limits>
+ #include <type_traits>
+ 
+@@ -151,6 +152,46 @@ namespace sw
+ 		return v;
+ 	}
+ 
++	template <int limit> class BoundedIndex
++	{
++	public:
++		BoundedIndex(int index) : index(index) {}
++
++		inline int operator++(int) { return index++; }
++		inline int operator--(int) { return index--; }
++		inline void operator=(int i) { index = i; }
++
++		inline bool operator==(int i) { return index == i; }
++		inline bool operator!=(int i) { return index != i; }
++		inline bool operator<(int i) { return index < i; }
++		inline bool operator>(int i) { return index > i; }
++		inline bool operator<=(int i) { return index <= i; }
++		inline bool operator>=(int i) { return index >= i; }
++
++		inline operator int()
++		{
++			if(index < 0)
++			{
++#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
++				assert(false);
++#endif
++				return 0;
++			}
++			else if(index >= limit)
++			{
++#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
++				assert(false);
++#endif
++				return limit - 1;
++			}
++
++			return index;
++		}
++
++	private:
++		int index = 0;
++	};
++
+ 	// The OFFSET macro is a generalization of the offsetof() macro defined in <cstddef>.
+ 	// It allows e.g. getting the offset of array elements, even when indexed dynamically.
+ 	// We cast the address '32' and subtract it again, because null-dereference is undefined behavior.
+diff --git a/src/Main/Config.hpp b/src/Main/Config.hpp
+index 764bfed1e7a159715f5d269e88d0d9ab578b778f..f875085452d0255d78b60ad9313e035d4ab3691f 100644
+--- a/src/Main/Config.hpp
++++ b/src/Main/Config.hpp
+@@ -97,6 +97,11 @@ namespace sw
+ 		MAX_TEXTURE_LOD = MIPMAP_LEVELS - 2,   // Trilinear accesses lod+1
+ 		RENDERTARGETS = 8,
+ 		NUM_TEMPORARY_REGISTERS = 4096,
++		MAX_SHADER_CALL_SITES = 2048,
++		MAX_SHADER_NESTED_LOOPS = 4,
++		MAX_SHADER_NESTED_IFS = 24 + 24,
++		MAX_SHADER_CALL_STACK_SIZE = 16,
++		MAX_SHADER_ENABLE_STACK_SIZE = 1 + 24,
+ 	};
+ }
+ 
+diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
+index 3cedbce8debcc7a1f8d22a7e687ea5673f33d01f..f8637209323b7dfe52b1736a9b15f0285f987331 100644
+--- a/src/Shader/PixelProgram.cpp
++++ b/src/Shader/PixelProgram.cpp
+@@ -828,7 +828,7 @@ namespace sw
+ 
+ 	Int4 PixelProgram::enableMask(const Shader::Instruction *instruction)
+ 	{
+-		Int4 enable = instruction->analysisBranch ? Int4(enableStack[enableIndex]) : Int4(0xFFFFFFFF);
++		Int4 enable = instruction->analysisBranch ? Int4(enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))]) : Int4(0xFFFFFFFF);
+ 
+ 		if(!whileTest)
+ 		{
+@@ -1343,7 +1343,7 @@ namespace sw
+ 
+ 	void PixelProgram::BREAK()
+ 	{
+-		enableBreak = enableBreak & ~enableStack[enableIndex];
++		enableBreak = enableBreak & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 	}
+ 
+ 	void PixelProgram::BREAKC(Vector4f &src0, Vector4f &src1, Control control)
+@@ -1379,14 +1379,14 @@ namespace sw
+ 
+ 	void PixelProgram::BREAK(Int4 &condition)
+ 	{
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		enableBreak = enableBreak & ~condition;
+ 	}
+ 
+ 	void PixelProgram::CONTINUE()
+ 	{
+-		enableContinue = enableContinue & ~enableStack[enableIndex];
++		enableContinue = enableContinue & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 	}
+ 
+ 	void PixelProgram::TEST()
+@@ -1403,7 +1403,7 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		Int4 restoreLeave = enableLeave;
+@@ -1443,7 +1443,7 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		Int4 restoreLeave = enableLeave;
+@@ -1463,7 +1463,7 @@ namespace sw
+ 			condition = ~condition;
+ 		}
+ 
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		if(!labelBlock[labelIndex])
+ 		{
+@@ -1472,11 +1472,11 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		enableIndex++;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 		Int4 restoreLeave = enableLeave;
+ 
+ 		Bool notAllFalse = SignMask(condition) != 0;
+@@ -1496,12 +1496,12 @@ namespace sw
+ 
+ 		if(isConditionalIf[ifDepth])
+ 		{
+-			Int4 condition = ~enableStack[enableIndex] & enableStack[enableIndex - 1];
++			Int4 condition = ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] & enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 			Bool notAllFalse = SignMask(condition) != 0;
+ 
+ 			branch(notAllFalse, falseBlock, endBlock);
+ 
+-			enableStack[enableIndex] = ~enableStack[enableIndex] & enableStack[enableIndex - 1];
++			enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] & enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 		}
+ 		else
+ 		{
+@@ -1655,10 +1655,10 @@ namespace sw
+ 
+ 	void PixelProgram::IF(Int4 &condition)
+ 	{
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		enableIndex++;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 
+ 		BasicBlock *trueBlock = Nucleus::createBasicBlock();
+ 		BasicBlock *falseBlock = Nucleus::createBasicBlock();
+@@ -1763,10 +1763,10 @@ namespace sw
+ 
+ 		const Vector4f &src = fetchRegister(temporaryRegister);
+ 		Int4 condition = As<Int4>(src.x);
+-		condition &= enableStack[enableIndex - 1];
++		condition &= enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 		if(shader->containsLeaveInstruction()) condition &= enableLeave;
+ 		if(shader->containsBreakInstruction()) condition &= enableBreak;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 
+ 		Bool notAllFalse = SignMask(condition) != 0;
+ 		branch(notAllFalse, loopBlock, endBlock);
+@@ -1838,7 +1838,7 @@ namespace sw
+ 
+ 	void PixelProgram::LEAVE()
+ 	{
+-		enableLeave = enableLeave & ~enableStack[enableIndex];
++		enableLeave = enableLeave & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		// FIXME: Return from function if all instances left
+ 		// FIXME: Use enableLeave in other control-flow constructs
+diff --git a/src/Shader/PixelProgram.hpp b/src/Shader/PixelProgram.hpp
+index 240938dd15820601ce2bf5e4ff6eb242ddd196e7..4ed3eef7545e27b56ceffa5a7cf33ebe9b7c287f 100644
+--- a/src/Shader/PixelProgram.hpp
++++ b/src/Shader/PixelProgram.hpp
+@@ -27,7 +27,7 @@ namespace sw
+ 			PixelRoutine(state, shader), r(shader->indirectAddressableTemporaries),
+ 			loopDepth(-1), ifDepth(0), loopRepDepth(0), currentLabel(-1), whileTest(false)
+ 		{
+-			for(int i = 0; i < 2048; ++i)
++			for(int i = 0; i < MAX_SHADER_CALL_SITES; ++i)
+ 			{
+ 				labelBlock[i] = 0;
+ 			}
+@@ -67,17 +67,17 @@ namespace sw
+ 
+ 		// DX9 specific variables
+ 		Vector4f p0;
+-		Array<Int, 4> aL;
+-		Array<Int, 4> increment;
+-		Array<Int, 4> iteration;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> aL;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> increment;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> iteration;
+ 
+ 		Int loopDepth;    // FIXME: Add support for switch
+ 		Int stackIndex;   // FIXME: Inc/decrement callStack
+-		Array<UInt, 16> callStack;
++		Array<UInt, MAX_SHADER_CALL_STACK_SIZE> callStack;
+ 
+ 		// Per pixel based on conditions reached
+ 		Int enableIndex;
+-		Array<Int4, 1 + 24> enableStack;
++		Array<Int4, MAX_SHADER_ENABLE_STACK_SIZE> enableStack;
+ 		Int4 enableBreak;
+ 		Int4 enableContinue;
+ 		Int4 enableLeave;
+@@ -152,18 +152,18 @@ namespace sw
+ 		void RET();
+ 		void LEAVE();
+ 
+-		int ifDepth;
+-		int loopRepDepth;
+-		int currentLabel;
++		BoundedIndex<MAX_SHADER_NESTED_IFS> ifDepth = 0;
++		BoundedIndex<MAX_SHADER_NESTED_LOOPS> loopRepDepth = 0;
++		BoundedIndex<MAX_SHADER_CALL_SITES> currentLabel = -1;
+ 		bool whileTest;
+ 
+-		BasicBlock *ifFalseBlock[24 + 24];
+-		BasicBlock *loopRepTestBlock[4];
+-		BasicBlock *loopRepEndBlock[4];
+-		BasicBlock *labelBlock[2048];
+-		std::vector<BasicBlock*> callRetBlock[2048];
++		BasicBlock *ifFalseBlock[MAX_SHADER_NESTED_IFS];
++		BasicBlock *loopRepTestBlock[MAX_SHADER_NESTED_LOOPS];
++		BasicBlock *loopRepEndBlock[MAX_SHADER_NESTED_LOOPS];
++		BasicBlock *labelBlock[MAX_SHADER_CALL_SITES];
++		std::vector<BasicBlock*> callRetBlock[MAX_SHADER_CALL_SITES];
+ 		BasicBlock *returnBlock;
+-		bool isConditionalIf[24 + 24];
++		bool isConditionalIf[MAX_SHADER_NESTED_IFS];
+ 	};
+ }
+ 
+diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
+index 36192c93c7473e7c4bc140843ad2c16ca11d3788..ed185d1c0c139bf971e44d7a1c2830de28a9c6ff 100644
+--- a/src/Shader/Shader.cpp
++++ b/src/Shader/Shader.cpp
+@@ -1877,13 +1877,13 @@ namespace sw
+ 	// This is used to know what basic block to return to.
+ 	void Shader::analyzeCallSites()
+ 	{
+-		int callSiteIndex[2048] = {0};
++		int callSiteIndex[MAX_SHADER_CALL_SITES] = {0};
+ 
+ 		for(auto &inst : instruction)
+ 		{
+ 			if(inst->opcode == OPCODE_CALL || inst->opcode == OPCODE_CALLNZ)
+ 			{
+-				int label = inst->dst.label;
++				int label = sw::min(inst->dst.label, (unsigned int)(MAX_SHADER_CALL_SITES));
+ 
+ 				inst->dst.callSite = callSiteIndex[label]++;
+ 			}
+diff --git a/src/Shader/VertexProgram.cpp b/src/Shader/VertexProgram.cpp
+index ad4e37bd4e5c1e93bc6728d5eaba19caf7f95e92..694f05179d6df328ef6f64a882d428422d7e86d6 100644
+--- a/src/Shader/VertexProgram.cpp
++++ b/src/Shader/VertexProgram.cpp
+@@ -31,7 +31,7 @@ namespace sw
+ 		currentLabel = -1;
+ 		whileTest = false;
+ 
+-		for(int i = 0; i < 2048; i++)
++		for(int i = 0; i < MAX_SHADER_CALL_SITES; i++)
+ 		{
+ 			labelBlock[i] = 0;
+ 		}
+@@ -978,7 +978,7 @@ namespace sw
+ 
+ 	Int4 VertexProgram::enableMask(const Shader::Instruction *instruction)
+ 	{
+-		Int4 enable = instruction->analysisBranch ? Int4(enableStack[enableIndex]) : Int4(0xFFFFFFFF);
++		Int4 enable = instruction->analysisBranch ? Int4(enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))]) : Int4(0xFFFFFFFF);
+ 
+ 		if(!whileTest)
+ 		{
+@@ -1060,7 +1060,7 @@ namespace sw
+ 
+ 	void VertexProgram::BREAK()
+ 	{
+-		enableBreak = enableBreak & ~enableStack[enableIndex];
++		enableBreak = enableBreak & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 	}
+ 
+ 	void VertexProgram::BREAKC(Vector4f &src0, Vector4f &src1, Control control)
+@@ -1096,14 +1096,14 @@ namespace sw
+ 
+ 	void VertexProgram::BREAK(Int4 &condition)
+ 	{
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		enableBreak = enableBreak & ~condition;
+ 	}
+ 
+ 	void VertexProgram::CONTINUE()
+ 	{
+-		enableContinue = enableContinue & ~enableStack[enableIndex];
++		enableContinue = enableContinue & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 	}
+ 
+ 	void VertexProgram::TEST()
+@@ -1120,7 +1120,7 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		Int4 restoreLeave = enableLeave;
+@@ -1160,7 +1160,7 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		Int4 restoreLeave = enableLeave;
+@@ -1180,7 +1180,7 @@ namespace sw
+ 			condition = ~condition;
+ 		}
+ 
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		if(!labelBlock[labelIndex])
+ 		{
+@@ -1189,11 +1189,11 @@ namespace sw
+ 
+ 		if(callRetBlock[labelIndex].size() > 1)
+ 		{
+-			callStack[stackIndex++] = UInt(callSiteIndex);
++			callStack[Min(stackIndex++, Int(MAX_SHADER_CALL_STACK_SIZE))] = UInt(callSiteIndex);
+ 		}
+ 
+ 		enableIndex++;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 		Int4 restoreLeave = enableLeave;
+ 
+ 		Bool notAllFalse = SignMask(condition) != 0;
+@@ -1213,12 +1213,12 @@ namespace sw
+ 
+ 		if(isConditionalIf[ifDepth])
+ 		{
+-			Int4 condition = ~enableStack[enableIndex] & enableStack[enableIndex - 1];
++			Int4 condition = ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] & enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 			Bool notAllFalse = SignMask(condition) != 0;
+ 
+ 			branch(notAllFalse, falseBlock, endBlock);
+ 
+-			enableStack[enableIndex] = ~enableStack[enableIndex] & enableStack[enableIndex - 1];
++			enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] & enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 		}
+ 		else
+ 		{
+@@ -1372,10 +1372,10 @@ namespace sw
+ 
+ 	void VertexProgram::IF(Int4 &condition)
+ 	{
+-		condition &= enableStack[enableIndex];
++		condition &= enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		enableIndex++;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 
+ 		BasicBlock *trueBlock = Nucleus::createBasicBlock();
+ 		BasicBlock *falseBlock = Nucleus::createBasicBlock();
+@@ -1481,10 +1481,10 @@ namespace sw
+ 
+ 		const Vector4f &src = fetchRegister(temporaryRegister);
+ 		Int4 condition = As<Int4>(src.x);
+-		condition &= enableStack[enableIndex - 1];
++		condition &= enableStack[Min(enableIndex - 1, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 		if(shader->containsLeaveInstruction()) condition &= enableLeave;
+ 		if(shader->containsBreakInstruction()) condition &= enableBreak;
+-		enableStack[enableIndex] = condition;
++		enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))] = condition;
+ 
+ 		Bool notAllFalse = SignMask(condition) != 0;
+ 		branch(notAllFalse, loopBlock, endBlock);
+@@ -1556,7 +1556,7 @@ namespace sw
+ 
+ 	void VertexProgram::LEAVE()
+ 	{
+-		enableLeave = enableLeave & ~enableStack[enableIndex];
++		enableLeave = enableLeave & ~enableStack[Min(enableIndex, Int(MAX_SHADER_ENABLE_STACK_SIZE))];
+ 
+ 		// FIXME: Return from function if all instances left
+ 		// FIXME: Use enableLeave in other control-flow constructs
+diff --git a/src/Shader/VertexProgram.hpp b/src/Shader/VertexProgram.hpp
+index 3c4199c6611198997326d387f787bcd7467558a3..8421078acaa9f89e311015f62e17d4825a3a6e82 100644
+--- a/src/Shader/VertexProgram.hpp
++++ b/src/Shader/VertexProgram.hpp
+@@ -39,18 +39,18 @@ namespace sw
+ 
+ 		RegisterArray<NUM_TEMPORARY_REGISTERS> r;   // Temporary registers
+ 		Vector4f a0;
+-		Array<Int, 4> aL;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> aL;
+ 		Vector4f p0;
+ 
+-		Array<Int, 4> increment;
+-		Array<Int, 4> iteration;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> increment;
++		Array<Int, MAX_SHADER_NESTED_LOOPS> iteration;
+ 
+ 		Int loopDepth;
+ 		Int stackIndex;   // FIXME: Inc/decrement callStack
+-		Array<UInt, 16> callStack;
++		Array<UInt, MAX_SHADER_CALL_STACK_SIZE> callStack;
+ 
+ 		Int enableIndex;
+-		Array<Int4, 1 + 24> enableStack;
++		Array<Int4, MAX_SHADER_ENABLE_STACK_SIZE> enableStack;
+ 		Int4 enableBreak;
+ 		Int4 enableContinue;
+ 		Int4 enableLeave;
+@@ -121,18 +121,18 @@ namespace sw
+ 		Vector4f sampleTexture(const Src &s, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+ 		Vector4f sampleTexture(int sampler, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+ 
+-		int ifDepth;
+-		int loopRepDepth;
+-		int currentLabel;
++		BoundedIndex<MAX_SHADER_NESTED_IFS> ifDepth = 0;
++		BoundedIndex<MAX_SHADER_NESTED_LOOPS> loopRepDepth = 0;
++		BoundedIndex<MAX_SHADER_CALL_SITES> currentLabel = -1;
+ 		bool whileTest;
+ 
+-		BasicBlock *ifFalseBlock[24 + 24];
+-		BasicBlock *loopRepTestBlock[4];
+-		BasicBlock *loopRepEndBlock[4];
+-		BasicBlock *labelBlock[2048];
+-		std::vector<BasicBlock*> callRetBlock[2048];
++		BasicBlock *ifFalseBlock[MAX_SHADER_NESTED_IFS];
++		BasicBlock *loopRepTestBlock[MAX_SHADER_NESTED_LOOPS];
++		BasicBlock *loopRepEndBlock[MAX_SHADER_NESTED_LOOPS];
++		BasicBlock *labelBlock[MAX_SHADER_CALL_SITES];
++		std::vector<BasicBlock*> callRetBlock[MAX_SHADER_CALL_SITES];
+ 		BasicBlock *returnBlock;
+-		bool isConditionalIf[24 + 24];
++		bool isConditionalIf[MAX_SHADER_NESTED_IFS];
+ 	};
+ }
+