已关闭
[ArkWeb][安全][上游社区漏洞修复][BUG-537835609] fragData逗号校验 #467
。创建于 18 天前关闭于 17 天前
[ArkWeb][安全][上游社区漏洞修复][BUG-537835609] fragData逗号校验 #467
已关闭
共 4 个文件变更+102-0
| @@ -370,6 +370,28 @@ bool IsESSL100ConstantExpression(TIntermNode *node) | |||
| 370 | { | 370 | { |
| 371 | return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst; | 371 | return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst; |
| 372 | } | 372 | } |
| 373 | + | ||
| 374 | +bool IsWholeArrayFragDataUsed(TIntermTyped *node) | ||
| 375 | +{ | ||
| 376 | + if (node->getQualifier() == EvqFragData) | ||
| 377 | + { | ||
| 378 | + return true; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + TIntermBinary *asBinary = node->getAsBinaryNode(); | ||
| 382 | + if (asBinary != nullptr && asBinary->getOp() == EOpComma) | ||
| 383 | + { | ||
| 384 | + return IsWholeArrayFragDataUsed(asBinary->getRight()); | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + // Either this is not ESSL 100 (where gl_FragData may be used), or gl_FragData is not used as a | ||
| 388 | + // whole array. | ||
| 389 | + // | ||
| 390 | + // Note: ESSL 100 does not allow arrays in ternary operator, so there is no need to check for | ||
| 391 | + // TIntermTernary here for a whole-array use of gl_FragData. | ||
| 392 | + return false; | ||
| 393 | +} | ||
| 394 | + | ||
| 373 | } // namespace | 395 | } // namespace |
| 374 | 396 | ||
| 375 | // This tracks each binding point's current default offset for inheritance of subsequent | 397 | // This tracks each binding point's current default offset for inheritance of subsequent |
| @@ -2784,6 +2806,22 @@ void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandid | |||
| 2784 | } | 2806 | } |
| 2785 | } | 2807 | } |
| 2786 | 2808 | ||
| 2809 | +void TParseContext::functionCallFragDataCheck(const TFunction *fnCandidate, | ||
| 2810 | + TIntermAggregate *fnCall) | ||
| 2811 | +{ | ||
| 2812 | + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) | ||
| 2813 | + { | ||
| 2814 | + TIntermTyped *argument = (*fnCall->getSequence())[i]->getAsTyped(); | ||
| 2815 | + if (IsWholeArrayFragDataUsed(argument)) | ||
| 2816 | + { | ||
| 2817 | + // The whole array is passed to the function. For validation purposes, assume all | ||
| 2818 | + // indices are accessed in the function. | ||
| 2819 | + ASSERT(argument->getType().isArray()); | ||
| 2820 | + mMaxFragDataArrayIndexUsed = argument->getType().getOutermostArraySize() - 1; | ||
| 2821 | + } | ||
| 2822 | + } | ||
| 2823 | +} | ||
| 2824 | + | ||
| 2787 | void TParseContext::checkInvariantVariableQualifier(bool invariant, | 2825 | void TParseContext::checkInvariantVariableQualifier(bool invariant, |
| 2788 | const TQualifier qualifier, | 2826 | const TQualifier qualifier, |
| 2789 | const TSourceLoc &invariantLocation) | 2827 | const TSourceLoc &invariantLocation) |
| @@ -9305,6 +9343,7 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCallImpl(TFunctionLookup * | |||
| 9305 | callNode->setLine(loc); | 9343 | callNode->setLine(loc); |
| 9306 | checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); | 9344 | checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); |
| 9307 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); | 9345 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); |
| 9346 | + functionCallFragDataCheck(fnCandidate, callNode); | ||
| 9308 | 9347 | ||
| 9309 | mCallGraph[mCurrentFunction].insert(fnCandidate); | 9348 | mCallGraph[mCurrentFunction].insert(fnCandidate); |
| 9310 | mIRBuilder.callFunction(mFunctionToId.at(fnCandidate)); | 9349 | mIRBuilder.callFunction(mFunctionToId.at(fnCandidate)); |
| @@ -214,6 +214,7 @@ class TParseContext : angle::NonCopyable | |||
| 214 | bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, | 214 | bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, |
| 215 | const TLayoutQualifier &layoutQualifier); | 215 | const TLayoutQualifier &layoutQualifier); |
| 216 | void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); | 216 | void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); |
| 217 | + void functionCallFragDataCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); | ||
| 217 | void checkInvariantVariableQualifier(bool invariant, | 218 | void checkInvariantVariableQualifier(bool invariant, |
| 218 | const TQualifier qualifier, | 219 | const TQualifier qualifier, |
| 219 | const TSourceLoc &invariantLocation); | 220 | const TSourceLoc &invariantLocation); |
| @@ -0,0 +1,34 @@ | |||
| 1 | +# Translator Unit Tests | ||
| 2 | + | ||
| 3 | +This directory contains historical unit tests for the ANGLE translator. Barring a few cases, they | ||
| 4 | +should be considered deprecated. **Do not add new tests to this directory.** | ||
| 5 | + | ||
| 6 | +The existing translator tests are severely limited in what they test. They often verify translation | ||
| 7 | +by asserting that a substring exists in the translated source or a node is found in the AST. | ||
| 8 | +However, neither is sufficient to ensure the transformations are done correctly. Often issues are | ||
| 9 | +discovered only when the shaders are used in a draw call and the translated source is given to the | ||
| 10 | +native driver. | ||
| 11 | + | ||
| 12 | +Furthermore, with the built-in assumptions about the way the AST works, these tests are incompatible | ||
| 13 | +with the upcoming IR. | ||
| 14 | + | ||
| 15 | +Instead, add end-to-end tests: | ||
| 16 | + | ||
| 17 | +* They can be easily tested on every backend | ||
| 18 | +* Functional testing with a draw call ensures the transformations are correct | ||
| 19 | +* Using the `GL_ANGLE_translated_shader_source` extension, we can still verify the output is as | ||
| 20 | + expected. This is a maintenance burden however and best avoided unless there is no _functional_ | ||
| 21 | + way to verify the transformation is done correctly, e.g. if the transformation works around | ||
| 22 | + undefined behavior which can't be reliably tested. | ||
| 23 | + | ||
| 24 | +To test translator validation, add new tests to `GLSLValidationTest.cpp`, which not only verifies | ||
| 25 | +that compilation fails, but also has facilities to ensure the failure reason is as expected (and | ||
| 26 | +not, for example, a typo in the test) | ||
| 27 | + | ||
| 28 | +To test transformations, add new tests to `GLSLTest.cpp` that would fail if the transformation in | ||
| 29 | +question is not done. By using ANGLE features to control the translator flag in question, the | ||
| 30 | +transformation can be force-enabled in a test suite, e.g. by instantiating with | ||
| 31 | +`ES3_OPENGL().enable(Feature::ScalarizeVecAndMatConstructorArgs)` | ||
| 32 | + | ||
| 33 | +To test that the output includes a specific text, if there is no better form of verification, add | ||
| 34 | +new tests to `GLSLOutputTest.cpp`. | ||
| @@ -4385,6 +4385,34 @@ void main() { | |||
| 4385 | "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT when gl_SecondaryFragDataEXT is used"); | 4385 | "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT when gl_SecondaryFragDataEXT is used"); |
| 4386 | } | 4386 | } |
| 4387 | 4387 | ||
| 4388 | +// Shader that writes to SecondaryFragData and passes FragData to a function. | ||
| 4389 | +TEST_P(GLSLValidationTest, BlendFuncExtendedPassFragDataToFunctionInCommaExpr) | ||
| 4390 | +{ | ||
| 4391 | + ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended")); | ||
| 4392 | + ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers")); | ||
| 4393 | + | ||
| 4394 | + GLint maxDrawBuffers = 0, maxDualSourceDrawBuffers = 0; | ||
| 4395 | + glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers); | ||
| 4396 | + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); | ||
| 4397 | + ANGLE_SKIP_TEST_IF(maxDualSourceDrawBuffers == maxDrawBuffers); | ||
| 4398 | + | ||
| 4399 | + constexpr char kFS[] = R"(#extension GL_EXT_draw_buffers : require | ||
| 4400 | + | ||
| 4401 | +precision mediump float; | ||
| 4402 | +void f(vec4 fragData[gl_MaxDrawBuffers]) | ||
| 4403 | +{ | ||
| 4404 | + fragData[0] = vec4(0.1); | ||
| 4405 | +} | ||
| 4406 | +void main() { | ||
| 4407 | + vec4 data[gl_MaxDrawBuffers]; | ||
| 4408 | + f((data, gl_FragData)); | ||
| 4409 | + gl_SecondaryFragDataEXT[0] = vec4(1.0); | ||
| 4410 | +})"; | ||
| 4411 | + validateError(GL_FRAGMENT_SHADER, kFS, | ||
| 4412 | + "array index for gl_FragData must be less than " | ||
| 4413 | + "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT when gl_SecondaryFragDataEXT is used"); | ||
| 4414 | +} | ||
| 4415 | + | ||
| 4388 | // Shader that writes to FragData at an index >= than gl_MaxDualSourceDrawBuffersEXT is fine if | 4416 | // Shader that writes to FragData at an index >= than gl_MaxDualSourceDrawBuffersEXT is fine if |
| 4389 | // SecondaryFragData is not used. | 4417 | // SecondaryFragData is not used. |
| 4390 | TEST_P(GLSLValidationTest, BlendFuncExtendedDataArrayOnly) | 4418 | TEST_P(GLSLValidationTest, BlendFuncExtendedDataArrayOnly) |