Skip to content

Commit 0ab8b46

Browse files
committed
Protected PropertyManager::Expand() from infinite loops when trying to expands property references that forms a circular reference.
For issue #72.
1 parent e70ea9b commit 0ab8b46

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

src/PropertyManager.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
namespace shellanything
3333
{
34+
static const int EXPANDING_MAX_ITERATIONS = 20;
3435

3536
PropertyManager::PropertyManager()
3637
{
@@ -130,13 +131,18 @@ namespace shellanything
130131

131132
std::string PropertyManager::Expand(const std::string & value) const
132133
{
134+
int count = 1;
133135
std::string previous = value;
134136
std::string output = ExpandOnce(value);
135-
while(output != previous)
137+
138+
//Prevent circular reference by expanding at most 20 times.
139+
while(output != previous && count <= EXPANDING_MAX_ITERATIONS)
136140
{
137141
previous = output;
138142
output = ExpandOnce(output);
143+
count++;
139144
}
145+
140146
return output;
141147
}
142148

@@ -150,11 +156,21 @@ namespace shellanything
150156
static const std::string token_open = "${";
151157
static const std::string token_close = "}";
152158

159+
//Prevent circular reference by dfining a counter which counts how many time a character position was expanded.
160+
int count = 1;
161+
size_t previous_pos = std::string::npos;
162+
153163
for(size_t i=0; i<output.size(); i++)
154164
{
155-
std::string name;
165+
//Count how many time we tried to expand this position
166+
if (i == previous_pos)
167+
count++; //same character as previous loop
168+
else
169+
count = 0; //that is a new character
170+
previous_pos = i;
156171

157172
//If we find a property reference token at this location...
173+
std::string name;
158174
if (strncmp(&output[i], token_open.c_str(), token_open.size()) == 0 && IsPropertyReference(token_open, token_close, output, i, name))
159175
{
160176
//Found a property reference at output[i]
@@ -164,9 +180,19 @@ namespace shellanything
164180
size_t token_length = token_open.size() + name.size() + token_close.size();
165181
output.replace(output.begin() + i, output.begin() + i + token_length, property_value);
166182

167-
//Keep i at the same value for the next loop to process the same character position.
168-
//This is required if the property value also contains property references.
169-
i--; //-1 since the next for loop will increase i by 1.
183+
//Prevent circular reference by expanding 20 times maximum.
184+
if (count < EXPANDING_MAX_ITERATIONS)
185+
{
186+
//Keep i at the same value for the next loop to process the same character position.
187+
//This is required if the property value also contains property references.
188+
i--; //-1 since the next for loop will increase i by 1.
189+
}
190+
else
191+
{
192+
//Reached the maximum of 20 loops.
193+
//Stop looking for property reference at this position.
194+
int a = 0;
195+
}
170196
}
171197
}
172198

test/TestPropertyManager.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ namespace shellanything { namespace test
257257
ASSERT_EQ("${quote}", expanded);
258258
}
259259
//--------------------------------------------------------------------------------------------------
260+
TEST_F(TestPropertyManager, testExpandCircularReference)
261+
{
262+
PropertyManager & pmgr = PropertyManager::GetInstance();
263+
264+
pmgr.SetProperty("first", "${second}");
265+
pmgr.SetProperty("second", "${first}");
266+
267+
//Property ${first} expands to "${second}" which expands back to "${first}" creating a circular reference.
268+
std::string expanded = pmgr.Expand("${first}");
269+
270+
//Nothing to assert.
271+
//We only care the Expand() method was not acting like an infinite loop.
272+
}
273+
//--------------------------------------------------------------------------------------------------
260274
TEST_F(TestPropertyManager, testEnvironmentVariableProperty)
261275
{
262276
PropertyManager & pmgr = PropertyManager::GetInstance();

0 commit comments

Comments
 (0)