-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add expression complexity and call stack depth limits.
git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@2254 736b8ea6-26fd-11df-bfd4-992fa37f6226
- Loading branch information
1 parent
b0f1b48
commit da8ea02
Showing
13 changed files
with
805 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// | ||
// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// | ||
|
||
#include "compiler/DetectCallDepth.h" | ||
#include "compiler/InfoSink.h" | ||
|
||
const int DetectCallDepth::FunctionNode::kInfiniteCallDepth; | ||
|
||
DetectCallDepth::FunctionNode::FunctionNode(const TString& fname) | ||
: name(fname), | ||
visit(PreVisit) | ||
{ | ||
} | ||
|
||
const TString& DetectCallDepth::FunctionNode::getName() const | ||
{ | ||
return name; | ||
} | ||
|
||
void DetectCallDepth::FunctionNode::addCallee( | ||
DetectCallDepth::FunctionNode* callee) | ||
{ | ||
for (size_t i = 0; i < callees.size(); ++i) { | ||
if (callees[i] == callee) | ||
return; | ||
} | ||
callees.push_back(callee); | ||
} | ||
|
||
int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth) | ||
{ | ||
ASSERT(visit == PreVisit); | ||
ASSERT(detectCallDepth); | ||
|
||
int maxDepth = depth; | ||
visit = InVisit; | ||
for (size_t i = 0; i < callees.size(); ++i) { | ||
switch (callees[i]->visit) { | ||
case InVisit: | ||
// cycle detected, i.e., recursion detected. | ||
return kInfiniteCallDepth; | ||
case PostVisit: | ||
break; | ||
case PreVisit: { | ||
// Check before we recurse so we don't go too depth | ||
if (detectCallDepth->checkExceedsMaxDepth(depth)) | ||
return depth; | ||
int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1); | ||
// Check after we recurse so we can exit immediately and provide info. | ||
if (detectCallDepth->checkExceedsMaxDepth(callDepth)) { | ||
detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName(); | ||
return callDepth; | ||
} | ||
maxDepth = std::max(callDepth, maxDepth); | ||
break; | ||
} | ||
default: | ||
UNREACHABLE(); | ||
break; | ||
} | ||
} | ||
visit = PostVisit; | ||
return maxDepth; | ||
} | ||
|
||
void DetectCallDepth::FunctionNode::reset() | ||
{ | ||
visit = PreVisit; | ||
} | ||
|
||
DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth) | ||
: TIntermTraverser(true, false, true, false), | ||
currentFunction(NULL), | ||
infoSink(infoSink), | ||
maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth) | ||
{ | ||
} | ||
|
||
DetectCallDepth::~DetectCallDepth() | ||
{ | ||
for (size_t i = 0; i < functions.size(); ++i) | ||
delete functions[i]; | ||
} | ||
|
||
bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node) | ||
{ | ||
switch (node->getOp()) | ||
{ | ||
case EOpPrototype: | ||
// Function declaration. | ||
// Don't add FunctionNode here because node->getName() is the | ||
// unmangled function name. | ||
break; | ||
case EOpFunction: { | ||
// Function definition. | ||
if (visit == PreVisit) { | ||
currentFunction = findFunctionByName(node->getName()); | ||
if (currentFunction == NULL) { | ||
currentFunction = new FunctionNode(node->getName()); | ||
functions.push_back(currentFunction); | ||
} | ||
} else if (visit == PostVisit) { | ||
currentFunction = NULL; | ||
} | ||
break; | ||
} | ||
case EOpFunctionCall: { | ||
// Function call. | ||
if (visit == PreVisit) { | ||
FunctionNode* func = findFunctionByName(node->getName()); | ||
if (func == NULL) { | ||
func = new FunctionNode(node->getName()); | ||
functions.push_back(func); | ||
} | ||
if (currentFunction) | ||
currentFunction->addCallee(func); | ||
} | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
return true; | ||
} | ||
|
||
bool DetectCallDepth::checkExceedsMaxDepth(int depth) | ||
{ | ||
return depth >= maxDepth; | ||
} | ||
|
||
void DetectCallDepth::resetFunctionNodes() | ||
{ | ||
for (size_t i = 0; i < functions.size(); ++i) { | ||
functions[i]->reset(); | ||
} | ||
} | ||
|
||
DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func) | ||
{ | ||
currentFunction = NULL; | ||
resetFunctionNodes(); | ||
|
||
int maxCallDepth = func->detectCallDepth(this, 1); | ||
|
||
if (maxCallDepth == FunctionNode::kInfiniteCallDepth) | ||
return kErrorRecursion; | ||
|
||
if (maxCallDepth >= maxDepth) | ||
return kErrorMaxDepthExceeded; | ||
|
||
return kErrorNone; | ||
} | ||
|
||
DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth() | ||
{ | ||
if (maxDepth != FunctionNode::kInfiniteCallDepth) { | ||
// Check all functions because the driver may fail on them | ||
// TODO: Before detectingRecursion, strip unused functions. | ||
for (size_t i = 0; i < functions.size(); ++i) { | ||
ErrorCode error = detectCallDepthForFunction(functions[i]); | ||
if (error != kErrorNone) | ||
return error; | ||
} | ||
} else { | ||
FunctionNode* main = findFunctionByName("main("); | ||
if (main == NULL) | ||
return kErrorMissingMain; | ||
|
||
return detectCallDepthForFunction(main); | ||
} | ||
|
||
return kErrorNone; | ||
} | ||
|
||
DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName( | ||
const TString& name) | ||
{ | ||
for (size_t i = 0; i < functions.size(); ++i) { | ||
if (functions[i]->getName() == name) | ||
return functions[i]; | ||
} | ||
return NULL; | ||
} | ||
|
Oops, something went wrong.