Added logic to check for cycles in the test dependency graph before any tests are run. Previously a cycle resulted in a segfault from stack overflow.
This commit is contained in:
parent
59f6f383e9
commit
d47ada823a
|
@ -15,6 +15,7 @@
|
|||
#include "cmCTest.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include <stdlib.h>
|
||||
#include <stack>
|
||||
|
||||
cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
|
||||
{
|
||||
|
@ -56,6 +57,10 @@ void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
|
|||
void cmCTestMultiProcessHandler::RunTests()
|
||||
{
|
||||
this->CheckResume();
|
||||
if(!this->CheckCycles())
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
|
||||
this->StartNextTests();
|
||||
while(this->Tests.size() != 0)
|
||||
|
@ -340,7 +345,7 @@ void cmCTestMultiProcessHandler::PrintTestList()
|
|||
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
|
||||
int count = 0;
|
||||
for (PropertiesMap::iterator it = this->Properties.begin();
|
||||
it != this->Properties.end(); it ++ )
|
||||
it != this->Properties.end(); ++it)
|
||||
{
|
||||
count++;
|
||||
cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
|
||||
|
@ -433,3 +438,47 @@ int cmCTestMultiProcessHandler::FindMaxIndex()
|
|||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
//Returns true if no cycles exist in the dependency graph
|
||||
bool cmCTestMultiProcessHandler::CheckCycles()
|
||||
{
|
||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||
"Checking test dependency graph..." << std::endl);
|
||||
for(TestMap::iterator it = this->Tests.begin();
|
||||
it != this->Tests.end(); ++it)
|
||||
{
|
||||
//DFS from each element to itself
|
||||
std::stack<int> s;
|
||||
std::vector<int> visited;
|
||||
s.push(it->first);
|
||||
visited.push_back(it->first);
|
||||
|
||||
while(!s.empty())
|
||||
{
|
||||
int test = s.top();
|
||||
s.pop();
|
||||
|
||||
for(TestSet::iterator d = this->Tests[test].begin();
|
||||
d != this->Tests[test].end(); ++d)
|
||||
{
|
||||
s.push(*d);
|
||||
for(std::vector<int>::iterator v = visited.begin();
|
||||
v != visited.end(); ++v)
|
||||
{
|
||||
if(*v == *d)
|
||||
{
|
||||
//cycle exists
|
||||
cmCTestLog(this->CTest, ERROR_MESSAGE, "Error: a cycle exists in "
|
||||
"the test dependency graph for the test \""
|
||||
<< this->Properties[*d]->Name << "\"." << std::endl
|
||||
<< "Please fix the cycle and run ctest again." << std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
visited.push_back(*d);
|
||||
}
|
||||
visited.pop_back();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,8 @@ protected:
|
|||
void RemoveTest(int index);
|
||||
//Check if we need to resume an interrupted test set
|
||||
void CheckResume();
|
||||
//Check if there are any circular dependencies
|
||||
bool CheckCycles();
|
||||
int FindMaxIndex();
|
||||
inline size_t GetProcessorsUsed(int index);
|
||||
// map from test number to set of depend tests
|
||||
|
|
Loading…
Reference in New Issue