This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Do not take address of empty string front
- From: François Dumont <frs dot dumont at gmail dot com>
- To: Jonathan Wakely <jwakely at redhat dot com>
- Cc: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>, gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 24 Jun 2015 22:13:49 +0200
- Subject: Re: Do not take address of empty string front
- Authentication-results: sourceware.org; auth=none
- References: <55853A70 dot 7030607 at gmail dot com> <20150620115928 dot GG2856 at redhat dot com> <20150622151000 dot GI2856 at redhat dot com>
On 22/06/2015 17:10, Jonathan Wakely wrote:
> On 20/06/15 12:59 +0100, Jonathan Wakely wrote:
>> On 20/06/15 12:03 +0200, François Dumont wrote:
>>> Hi
>>>
>>> 2 experimental tests are failing in debug mode because
>>> __do_str_codecvt is sometimes taking address of string front() and
>>> back() even if empty. It wasn't use so not a big issue but it still
>>> seems better to avoid. I propose to rather use string begin() to get
>>> buffer address.
>>
>> But derefencing begin() is still undefined for an empty string.
>> Shouldn't that fail for debug mode too?
It would if we were using basic_string debug implementation but we
aren't. We are just using normal implementation with some debug checks
which is not enough to detect invalid deference operations.
>> Why change one form of
>> undefined behaviour that we diagnose to another form that we don't
>> diagnose?
>>
>> It would be better if that function didn't do any work when the input
>> range is empty:
>>
>> --- a/libstdc++-v3/include/bits/locale_conv.h
>> +++ b/libstdc++-v3/include/bits/locale_conv.h
>> @@ -58,6 +58,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> _OutStr& __outstr, const _Codecvt& __cvt, _State&
>> __state,
>> size_t& __count, _Fn __fn)
>> {
>> + if (__first == __last)
>> + {
>> + __outstr.clear();
>> + return true;
>> + }
>> +
>> size_t __outchars = 0;
>> auto __next = __first;
>> const auto __maxlen = __cvt.max_length() + 1;
>
> This makes that change, and also moves wstring_convert into the
> ABI-tagged __cxx11 namespace, and fixes a copy&paste error in the
> exception thrown from wbuffer_convert.
>
> Tested powerpc64le-linux, committed to trunk.
>
> François, your changes to add extra checks in std::string are still
> useful separately.
>
I just applied attached patch then.
François
Index: include/bits/basic_string.h
===================================================================
--- include/bits/basic_string.h (revision 224914)
+++ include/bits/basic_string.h (working copy)
@@ -39,6 +39,7 @@
#include <ext/atomicity.h>
#include <ext/alloc_traits.h>
#include <debug/debug.h>
+
#if __cplusplus >= 201103L
#include <initializer_list>
#endif
@@ -903,7 +904,10 @@
*/
reference
front() noexcept
- { return operator[](0); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](0);
+ }
/**
* Returns a read-only (constant) reference to the data at the first
@@ -911,7 +915,10 @@
*/
const_reference
front() const noexcept
- { return operator[](0); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](0);
+ }
/**
* Returns a read/write reference to the data at the last
@@ -919,7 +926,10 @@
*/
reference
back() noexcept
- { return operator[](this->size() - 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](this->size() - 1);
+ }
/**
* Returns a read-only (constant) reference to the data at the
@@ -927,7 +937,10 @@
*/
const_reference
back() const noexcept
- { return operator[](this->size() - 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](this->size() - 1);
+ }
#endif
// Modifiers:
@@ -1506,7 +1519,10 @@
*/
void
pop_back() noexcept
- { _M_erase(size()-1, 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ _M_erase(size() - 1, 1);
+ }
#endif // C++11
/**
@@ -3308,7 +3324,10 @@
*/
reference
front()
- { return operator[](0); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](0);
+ }
/**
* Returns a read-only (constant) reference to the data at the first
@@ -3316,7 +3335,10 @@
*/
const_reference
front() const _GLIBCXX_NOEXCEPT
- { return operator[](0); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](0);
+ }
/**
* Returns a read/write reference to the data at the last
@@ -3324,7 +3346,10 @@
*/
reference
back()
- { return operator[](this->size() - 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](this->size() - 1);
+ }
/**
* Returns a read-only (constant) reference to the data at the
@@ -3332,7 +3357,10 @@
*/
const_reference
back() const _GLIBCXX_NOEXCEPT
- { return operator[](this->size() - 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ return operator[](this->size() - 1);
+ }
#endif
// Modifiers:
@@ -3819,7 +3847,10 @@
*/
void
pop_back() // FIXME C++11: should be noexcept.
- { erase(size()-1, 1); }
+ {
+ _GLIBCXX_DEBUG_ASSERT(!empty());
+ erase(size() - 1, 1);
+ }
#endif // C++11
/**