aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-02-09 12:32:43 +0100
committerJakub Jelinek <jakub@redhat.com>2021-02-09 12:32:43 +0100
commite14ea108faa6eba6a60a45ff0ca3099ce6ae45c2 (patch)
treed4db4d6eb0ccfa4830b757b17b3bdfc1dd83048d
parente5304598f1481886f9871cc024cb65ba34aa4be3 (diff)
downloadgcc-e14ea108faa6eba6a60a45ff0ca3099ce6ae45c2.zip
gcc-e14ea108faa6eba6a60a45ff0ca3099ce6ae45c2.tar.gz
gcc-e14ea108faa6eba6a60a45ff0ca3099ce6ae45c2.tar.bz2
string: Add a workaround for -Wstringop-overread false positives [PR98465]
In the PR there are several possibilities how to improve _M_disjunct at least in certain cases so that the compiler can figure out at least in some cases where __s is provably disjunct from _M_data() ... _M_data() + this->size() but it is probably GCC 12 material. The false positive warning is on this particular copy, which is done for non-disjunct pointers when __len2 > __len1 and the __s >= __p + __len1, i.e. __s used to point to the characters moved through _S_move a few lines earlier by __len2 - __len1 characters up to make space. That is why the _S_copy source is __s + __len2 - __len1. Unfortunately, when the compiler can't prove objects are disjunct, that copying from __s + __len2 - __len1 of __len2 characters can very well mean accessing characters the source object (if it is not disjunct) provably can't have. The following patch works around that by making the _S_copy be a __p based pointer instead of __s based pointer. __s + __len2 - __len1 and __p + (__s - __p) + (__len2 - __len1) have the same value and the latter may seem to be uselessly longer, but it seems at least currently in GIMPLE we keep it that way and so that is what the warning code during expansion will see, and only actually optimize it to __s + __len2 - __len1 during RTL when we lose information on what is a pointer and what is a mere offset with the same mode. So, in the end we emit exactly the same assembly, just without the false positive warning. 2021-02-09 Jakub Jelinek <jakub@redhat.com> PR middle-end/98465 * include/bits/basic_string.tcc (basic_string::_M_replace): When __s points to the characters moved by earlier _S_move, compute the source address using expression based on the __p pointer rather than __s pointer. * g++.dg/warn/Wstringop-overread-1.C: New test.
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstringop-overread-1.C12
-rw-r--r--libstdc++-v3/include/bits/basic_string.tcc7
2 files changed, 18 insertions, 1 deletions
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overread-1.C b/gcc/testsuite/g++.dg/warn/Wstringop-overread-1.C
new file mode 100644
index 0000000..f7ba617
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-overread-1.C
@@ -0,0 +1,12 @@
+// PR middle-end/98994
+// { dg-do compile }
+// { dg-additional-options "-Wstringop-overread -O2" }
+
+#include <string>
+
+const char constantString[] = {42, 53};
+
+void f(std::string& s)
+{
+ s.insert(0, static_cast<const char*>(constantString), 2);
+}
diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc
index 5beda8b..35b6086 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -478,7 +478,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__s + __len2 <= __p + __len1)
this->_S_move(__p, __s, __len2);
else if (__s >= __p + __len1)
- this->_S_copy(__p, __s + __len2 - __len1, __len2);
+ {
+ // Hint to middle end that __p and __s overlap
+ // (PR 98465).
+ const size_type __poff = (__s - __p) + (__len2 - __len1);
+ this->_S_copy(__p, __p + __poff, __len2);
+ }
else
{
const size_type __nleft = (__p + __len1) - __s;