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
5 changed files with 93 additions and 7 deletions
|
@ -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>
|
2018-12-13 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* src/filesystem/std-path.cc (SLASHSLASH_IS_ROOT_NAME): New macro to
|
* 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));
|
::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
|
||||||
++_M_cmpts._M_impl->_M_size;
|
++_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;
|
++_M_cmpts._M_impl->_M_size;
|
||||||
|
cmpt = parser.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.back() == '/')
|
if (s.back() == '/')
|
||||||
|
@ -1139,7 +1140,7 @@ path::_M_concat(basic_string_view<value_type> s)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (orig_filenamelen == 0)
|
else if (orig_filenamelen == 0 && extra.empty())
|
||||||
{
|
{
|
||||||
// Replace empty filename at end of original path.
|
// Replace empty filename at end of original path.
|
||||||
std::prev(output)->_M_pathname = it->str;
|
std::prev(output)->_M_pathname = it->str;
|
||||||
|
|
|
@ -137,6 +137,22 @@ test05()
|
||||||
s = second->native();
|
s = second->native();
|
||||||
p3 /= s;
|
p3 /= s;
|
||||||
VERIFY( p3.string() == "0/123456789/a/123456789" );
|
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
|
int
|
||||||
|
@ -147,4 +163,5 @@ main()
|
||||||
test03();
|
test03();
|
||||||
test04();
|
test04();
|
||||||
test05();
|
test05();
|
||||||
|
test06();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <testsuite_hooks.h>
|
#include <testsuite_hooks.h>
|
||||||
#include <testsuite_iterators.h>
|
#include <testsuite_iterators.h>
|
||||||
|
#include <testsuite_fs.h>
|
||||||
|
|
||||||
using std::filesystem::path;
|
using std::filesystem::path;
|
||||||
|
using __gnu_test::compare_paths;
|
||||||
|
|
||||||
void
|
void
|
||||||
test01()
|
test01()
|
||||||
|
@ -60,7 +62,7 @@ test01()
|
||||||
void
|
void
|
||||||
test02()
|
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";
|
path p = "0/1/2/3/4/5/6";
|
||||||
// The string_view aliases the path's internal string:
|
// 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
|
// Append that string_view, which must work correctly even though the
|
||||||
// internal string will be reallocated during the operation:
|
// internal string will be reallocated during the operation:
|
||||||
p += s;
|
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:
|
// Same again with a trailing slash:
|
||||||
path p2 = "0/1/2/3/4/5/";
|
path p2 = "0/1/2/3/4/5/";
|
||||||
s = p2.native();
|
s = p2.native();
|
||||||
p2 += s;
|
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:
|
// And aliasing one of the components of the path:
|
||||||
path p3 = "0/123456789";
|
path p3 = "0/123456789";
|
||||||
path::iterator second = std::next(p3.begin());
|
path::iterator second = std::next(p3.begin());
|
||||||
s = second->native();
|
s = second->native();
|
||||||
p3 += s;
|
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
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
test01();
|
test01();
|
||||||
test02();
|
test02();
|
||||||
|
test03();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <testsuite_fs.h>
|
#include <testsuite_fs.h>
|
||||||
|
#include <testsuite_hooks.h>
|
||||||
|
|
||||||
using std::filesystem::path;
|
using std::filesystem::path;
|
||||||
using __gnu_test::compare_paths;
|
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
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
test01();
|
test01();
|
||||||
|
test02();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue