On Fri, Jun 01, 2012 at 01:00:46PM +0200, Florian Weimer wrote:
> I forgot to send this to the libstdc++ list the first time.
> 
> This patch evaluates _FORTIFY_SOURCE in a way similar to GNU libc.
> If set, std::vector::operator[] throws if the index is out of bounds.
> This is compliant with the standard because such usage triggers
> undefined behavior.  _FORTIFY_SOURCE users expect some performance hit.
> 
> In contrast to debugging mode, this does not change ABI and is more
> widely applicable.
> 
> Okay for trunk?

Have you looked at the assembly differences with this in?
I wonder e.g. if we don't need to add __builtin_expect around the
_M_range_check test.  As it needs to read in many cases two pointers,
subtract them (+ divide by size of entry (or shift right if power of two))
and compare that to something likely in a register, it is likely to be more
expensive than most of other _FORTIFY_SOURCE checks, but perhaps bearable.
Also, I wonder if the addition of a throw spot (even in cold .text chunk)
doesn't add too much cost (code having to deal with possible EH even when
otherwise it wouldn't be expected) and whether calling __chk_fail () in
that case instead wouldn't be cheaper.  Even in C++ memcpy etc. _FORTIFY_SOURCE
failures will result in __chk_fail, not throwing some exception, so
operator[] on std::vector could work the same.  operator[] is documented
as not doing the range check (unlike ->at()), so you probably need to
tweak the documentation too.

> 2012-05-29  Florian Weimer  <fwei...@redhat.com>
> 
>       * include/bits/stl_vector.h (vector::_M_fortify_range_check):
>       New.
>       * (vector::operator[]): Call it.
>       * testsuite/23_containers/vector/element_access/2.cc: New.
>
> Index: libstdc++-v3/include/bits/stl_vector.h
> ===================================================================
> --- libstdc++-v3/include/bits/stl_vector.h    (revision 187951)
> +++ libstdc++-v3/include/bits/stl_vector.h    (working copy)
> @@ -768,7 +768,10 @@
>         */
>        reference
>        operator[](size_type __n)
> -      { return *(this->_M_impl._M_start + __n); }
> +      {
> +     _M_fortify_range_check(__n);
> +     return *(this->_M_impl._M_start + __n);
> +      }
>  
>        /**
>         *  @brief  Subscript access to the data contained in the %vector.
> @@ -783,7 +786,10 @@
>         */
>        const_reference
>        operator[](size_type __n) const
> -      { return *(this->_M_impl._M_start + __n); }
> +      { 
> +     _M_fortify_range_check(__n);
> +     return *(this->_M_impl._M_start + __n);
> +      }
>  
>      protected:
>        /// Safety check used only from at().
> @@ -794,6 +800,16 @@
>         __throw_out_of_range(__N("vector::_M_range_check"));
>        }
>  
> +      /// Range check used by operator[].
> +      /// No-op unless _FORTIFY_SOURCE is enabled.
> +      void
> +      _M_fortify_range_check(size_type __n) const
> +      {
> +#if defined _FORTIFY_SOURCE && _FORTIFY_SOURCE > 0
> +     _M_range_check(__n);
> +#endif
> +      }
> +
>      public:
>        /**
>         *  @brief  Provides access to the data contained in the %vector.

        Jakub

Reply via email to