PR libstdc++/71044 fix off-by-one errors introduced recently
The recent changes to append/concat directly from strings (without constructing paths) introduced regressions where one of the components could be omitted from the iteration sequence in the result. PR libstdc++/71044 * src/filesystem/std-path.cc (path::_M_append): Fix off-by-one error that caused a component to be lost from the iteration sequence. (path::_M_concat): Likewise. * testsuite/27_io/filesystem/path/append/source.cc: Test appending long strings. * testsuite/27_io/filesystem/path/concat/strings.cc: Test concatenating long strings. * testsuite/27_io/filesystem/path/construct/string_view.cc: Test construction from long string. From-SVN: r267222
This commit is contained in:
parent
00fd062886
commit
2017595dfa
@ -1,3 +1,16 @@
|
||||
2018-12-17 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/71044
|
||||
* src/filesystem/std-path.cc (path::_M_append): Fix off-by-one error
|
||||
that caused a component to be lost from the iteration sequence.
|
||||
(path::_M_concat): Likewise.
|
||||
* testsuite/27_io/filesystem/path/append/source.cc: Test appending
|
||||
long strings.
|
||||
* testsuite/27_io/filesystem/path/concat/strings.cc: Test
|
||||
concatenating long strings.
|
||||
* testsuite/27_io/filesystem/path/construct/string_view.cc: Test
|
||||
construction from long string.
|
||||
|
||||
2018-12-13 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* src/filesystem/std-path.cc (SLASHSLASH_IS_ROOT_NAME): New macro to
|
||||
|
@ -781,10 +781,11 @@ path::_M_append(basic_string_view<value_type> s)
|
||||
::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
|
||||
++_M_cmpts._M_impl->_M_size;
|
||||
}
|
||||
for (auto c = parser.next(); c.valid(); c = parser.next())
|
||||
while (cmpt.valid())
|
||||
{
|
||||
::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
|
||||
::new(output++) _Cmpt(cmpt.str, cmpt.type, parser.offset(cmpt));
|
||||
++_M_cmpts._M_impl->_M_size;
|
||||
cmpt = parser.next();
|
||||
}
|
||||
|
||||
if (s.back() == '/')
|
||||
@ -1139,7 +1140,7 @@ path::_M_concat(basic_string_view<value_type> s)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (orig_filenamelen == 0)
|
||||
else if (orig_filenamelen == 0 && extra.empty())
|
||||
{
|
||||
// Replace empty filename at end of original path.
|
||||
std::prev(output)->_M_pathname = it->str;
|
||||
|
@ -137,6 +137,22 @@ test05()
|
||||
s = second->native();
|
||||
p3 /= s;
|
||||
VERIFY( p3.string() == "0/123456789/a/123456789" );
|
||||
}
|
||||
|
||||
void
|
||||
test06()
|
||||
{
|
||||
const std::string s0 = "a/b/c";
|
||||
path p = s0;
|
||||
std::string s;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
s += "0/1/2/3/4/5/6/7/8/9/";
|
||||
// append a long string with many components
|
||||
test(p, s.c_str());
|
||||
|
||||
// Same again but with a trailing slash on the left operand:
|
||||
path p2 = s0 + '/';
|
||||
test(p2, s.c_str());
|
||||
}
|
||||
|
||||
int
|
||||
@ -147,4 +163,5 @@ main()
|
||||
test03();
|
||||
test04();
|
||||
test05();
|
||||
test06();
|
||||
}
|
||||
|
@ -24,8 +24,10 @@
|
||||
#include <filesystem>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_iterators.h>
|
||||
#include <testsuite_fs.h>
|
||||
|
||||
using std::filesystem::path;
|
||||
using __gnu_test::compare_paths;
|
||||
|
||||
void
|
||||
test01()
|
||||
@ -60,7 +62,7 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
std::basic_string_view<path::value_type> s;
|
||||
std::basic_string_view<path::value_type> s, expected;
|
||||
|
||||
path p = "0/1/2/3/4/5/6";
|
||||
// The string_view aliases the path's internal string:
|
||||
@ -68,25 +70,54 @@ test02()
|
||||
// Append that string_view, which must work correctly even though the
|
||||
// internal string will be reallocated during the operation:
|
||||
p += s;
|
||||
VERIFY( p.string() == "0/1/2/3/4/5/60/1/2/3/4/5/6" );
|
||||
compare_paths(p, "0/1/2/3/4/5/60/1/2/3/4/5/6");
|
||||
|
||||
// Same again with a trailing slash:
|
||||
path p2 = "0/1/2/3/4/5/";
|
||||
s = p2.native();
|
||||
p2 += s;
|
||||
VERIFY( p2.string() == "0/1/2/3/4/5/0/1/2/3/4/5/" );
|
||||
compare_paths(p2, "0/1/2/3/4/5/0/1/2/3/4/5/");
|
||||
|
||||
// And aliasing one of the components of the path:
|
||||
path p3 = "0/123456789";
|
||||
path::iterator second = std::next(p3.begin());
|
||||
s = second->native();
|
||||
p3 += s;
|
||||
VERIFY( p3.string() == "0/123456789123456789" );
|
||||
compare_paths(p3, "0/123456789123456789" );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
const std::string s0 = "a/b/c";
|
||||
path p = s0;
|
||||
std::string s;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
s += "0/1/2/3/4/5/6/7/8/9/";
|
||||
// concat a long string with many components:
|
||||
p += s;
|
||||
compare_paths(p, path(s0+s));
|
||||
|
||||
// Same again but with a trailing slash on the left operand:
|
||||
path p2 = s0 + '/';
|
||||
p2 += s;
|
||||
compare_paths(p2, path(s0+'/'+s));
|
||||
|
||||
// And again but with a leading slash on the right operand:
|
||||
path p3 = s0;
|
||||
s.insert(0, 1, '/');
|
||||
p3 += s;
|
||||
compare_paths(p2, path(s0+s));
|
||||
|
||||
// And again but with a slash on both operands:
|
||||
path p4 = s0 + '/';
|
||||
p4 += s;
|
||||
compare_paths(p4, path(s0+'/'+s));
|
||||
}
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <testsuite_fs.h>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using std::filesystem::path;
|
||||
using __gnu_test::compare_paths;
|
||||
@ -49,8 +50,31 @@ test01()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
std::string s;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
s += "0/1/2/3/4/5/6/7/8/9/";
|
||||
// Construct a path with a large number of components:
|
||||
path p = s;
|
||||
auto iter = p.begin();
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
char c = '0' + i % 10;
|
||||
std::string_view sv(&c, 1);
|
||||
VERIFY( iter != p.end() );
|
||||
compare_paths( *iter, sv );
|
||||
++iter;
|
||||
}
|
||||
VERIFY( iter != p.end() );
|
||||
VERIFY( iter->native().empty() );
|
||||
VERIFY( ++iter == p.end() );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user