James Kanze
2010-02-12 19:37:12 UTC
I'm getting a very strange crash with the following program:
--------------------IteratorProblem.cpp------------------
typedef std::string::const_iterator text_iterator;
std::string r(std::string const& orig, std::string const& before,
std::string const& after)
{
std::string retval;
text_iterator current = orig.begin();
text_iterator end = orig.end();
text_iterator next = std::search(current, end, before.begin(),
before.end());
while (next != end)
{
retval.insert(retval.end(), current, next);
retval.insert(retval.end(), after.begin(), after.end());
current = next + before.size();
next = std::search(current, end, before.begin(),
before.end());
}
retval.insert(retval.end(), current, next);
return retval;
}
void r(std::string* text, std::string const& before, std::string
const& after)
{
std::string retval(r(*text, before, after));
text->swap(retval);
}
std::string f()
{
return r("double", "@", "");
}
std::string g(bool b,std::string const& a, std::string const& c)
{
return (b ? "Failed<" + a + '>' : a) + ' ' + c + ';';
}
std::string h()
{
std::string ret(g(true, f(), "x"));
r(&ret, ">>", "> >");
return ret;
}
int
main()
{
std::cout << "before:" << std::endl;
std::string s(h());
std::cout << "after: out = \"" << s << '\"' << std::endl;
return 0;
}
--------------------IteratorProblem.cpp------------------
The problem depends on the compiler options; for various
reasons, we are using
/D "_DEBUG" /D "_HAS_ITERATOR_DEBUGGING=0" /EHa /MDd /Zi
in debug mode, and this triggers the crash---if drop the
_HAS_ITERATOR_DEBUGGING line (so it defaults to 1 with _DEBUG),
everything works (except that the real code we are trying to
debug runs too slowly to make this acceptable). The funny thing
is, if I change the first parameter of g to false (in the call
in h), it also works; the problem only occurs if the final
string in r is greater than 15 characters (the small string
optimization buffer, and the capacity of a newly constructed
string). Checking in the debugger, it seems that despite the
_HAS_ITERATOR_DEBUGGING=0, some of the iterators are chaining in
with the owning string, but the chain is broken.
Given the somewhat special conditions required to trigger this
(a reallocation is necessary in "retval"), I suspect an error
somewhere in the library, but it's also possible that Microsoft
forbids this combination of options. (I can imagine cases where
it's likely to cause problems, but the library code seems to
take steps to guard against it.) So which is it? (And if it is
an illegal combination of options, where is this documented?)
--
James Kanze
--------------------IteratorProblem.cpp------------------
typedef std::string::const_iterator text_iterator;
std::string r(std::string const& orig, std::string const& before,
std::string const& after)
{
std::string retval;
text_iterator current = orig.begin();
text_iterator end = orig.end();
text_iterator next = std::search(current, end, before.begin(),
before.end());
while (next != end)
{
retval.insert(retval.end(), current, next);
retval.insert(retval.end(), after.begin(), after.end());
current = next + before.size();
next = std::search(current, end, before.begin(),
before.end());
}
retval.insert(retval.end(), current, next);
return retval;
}
void r(std::string* text, std::string const& before, std::string
const& after)
{
std::string retval(r(*text, before, after));
text->swap(retval);
}
std::string f()
{
return r("double", "@", "");
}
std::string g(bool b,std::string const& a, std::string const& c)
{
return (b ? "Failed<" + a + '>' : a) + ' ' + c + ';';
}
std::string h()
{
std::string ret(g(true, f(), "x"));
r(&ret, ">>", "> >");
return ret;
}
int
main()
{
std::cout << "before:" << std::endl;
std::string s(h());
std::cout << "after: out = \"" << s << '\"' << std::endl;
return 0;
}
--------------------IteratorProblem.cpp------------------
The problem depends on the compiler options; for various
reasons, we are using
/D "_DEBUG" /D "_HAS_ITERATOR_DEBUGGING=0" /EHa /MDd /Zi
in debug mode, and this triggers the crash---if drop the
_HAS_ITERATOR_DEBUGGING line (so it defaults to 1 with _DEBUG),
everything works (except that the real code we are trying to
debug runs too slowly to make this acceptable). The funny thing
is, if I change the first parameter of g to false (in the call
in h), it also works; the problem only occurs if the final
string in r is greater than 15 characters (the small string
optimization buffer, and the capacity of a newly constructed
string). Checking in the debugger, it seems that despite the
_HAS_ITERATOR_DEBUGGING=0, some of the iterators are chaining in
with the owning string, but the chain is broken.
Given the somewhat special conditions required to trigger this
(a reallocation is necessary in "retval"), I suspect an error
somewhere in the library, but it's also possible that Microsoft
forbids this combination of options. (I can imagine cases where
it's likely to cause problems, but the library code seems to
take steps to guard against it.) So which is it? (And if it is
an illegal combination of options, where is this documented?)
--
James Kanze