This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Fortification of STL
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Benjamin Kosnik <bkoz at redhat dot com>
- Cc: libstdc++ at gcc dot gnu dot org, Ulrich Drepper <drepper at redhat dot com>
- Date: Mon, 3 Sep 2007 09:34:35 -0400
- Subject: Fortification of STL
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
Several headers in libstdc++-v3 use __builtin_memmove, __builtin_memcpy
or __builtin_memset directly instead of making sure <string.h> is included
and using memmove/memcpy/memset. I assume that's for header pollution
reasons. Here is just what I found that could take advantage of the
protection, say std::copy, std::move or std::assign in a badly written
program could overflow a buffer and be catcheable either at compile time,
or at runtime.
The following patch of course is not meant to be directly used,
this should only be enabled if
1) _FORTIFY_SOURCE is defined
2) __OPTIMIZE__ > 0
3) we know the C library provides the checking functions (__memcpy_chk,
__memmove_chk, __memset_chk in this case)
and having conditionals everywhere is jus too ugly to live with.
Guess some __gnu_* namespace could have an __attribute__((always_inline))
memcpy, memmove and memset routine that would either return
__builtin_* or __builtin___*_chk depending on preprocessor macros...
In the libstdc++-v3 testsuite no violations were reported at compile time
and only 3 tests called the __mem*_chk routines at runtime, but that of
course doesn't mean random C++ sources don't hit it much more often.
--- libstdc++-v3/include/bits/stl_algobase.h.jj 2007-08-13 15:11:18.000000000 +0200
+++ libstdc++-v3/include/bits/stl_algobase.h 2007-09-03 15:12:28.000000000 +0200
@@ -347,8 +347,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
static _Tp*
copy(const _Tp* __first, const _Tp* __last, _Tp* __result)
{
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memmove_chk(__result, __first,
+ sizeof(_Tp) * (__last - __first),
+ __builtin_object_size (__result, 0));
+#else
__builtin_memmove(__result, __first,
sizeof(_Tp) * (__last - __first));
+#endif
return __result + (__last - __first);
}
};
@@ -464,7 +470,13 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__copy_b(const _Tp* __first, const _Tp* __last, _Tp* __result)
{
const ptrdiff_t _Num = __last - __first;
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memmove_chk(__result - _Num, __first,
+ sizeof(_Tp) * _Num,
+ __builtin_object_size (__result - _Num, 0));
+#else
__builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num);
+#endif
return __result - _Num;
}
};
@@ -560,17 +572,40 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
// Specialization: for char types we can use memset.
inline void
__fill_aux(unsigned char* __first, unsigned char* __last, unsigned char __c)
- { __builtin_memset(__first, __c, __last - __first); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memset_chk(__first, __c, __last - __first,
+ __builtin_object_size (__first, 0));
+#else
+ __builtin_memset(__first, __c, __last - __first);
+#endif
+ }
inline void
__fill_aux(signed char* __first, signed char* __last, signed char __c)
- { __builtin_memset(__first, static_cast<unsigned char>(__c),
- __last - __first); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memset_chk(__first, static_cast<unsigned char>(__c),
+ __last - __first,
+ __builtin_object_size (__first, 0));
+#else
+ __builtin_memset(__first, static_cast<unsigned char>(__c),
+ __last - __first);
+#endif
+ }
inline void
__fill_aux(char* __first, char* __last, char __c)
- { __builtin_memset(__first, static_cast<unsigned char>(__c),
- __last - __first); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memset_chk(__first, static_cast<unsigned char>(__c),
+ __last - __first,
+ __builtin_object_size (__first, 0));
+#else
+ __builtin_memset(__first, static_cast<unsigned char>(__c),
+ __last - __first);
+#endif
+ }
/**
* @brief Fills the range [first,last) with copies of value.
--- libstdc++-v3/include/bits/char_traits.h.jj 2007-08-23 23:31:25.000000000 +0200
+++ libstdc++-v3/include/bits/char_traits.h 2007-09-03 14:29:47.000000000 +0200
@@ -187,6 +187,14 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
{
return static_cast<_CharT*>(__builtin_memmove(__s1, __s2,
__n * sizeof(char_type)));
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ return static_cast<_CharT*>(__builtin___memmove_chk(__s1, __s2,
+ __n * sizeof(char_type),
+ __builtin_object_size (__s1, 0)));
+#else
+ return static_cast<_CharT*>(__builtin_memmove(__s1, __s2,
+ __n * sizeof(char_type)));
+#endif
}
template<typename _CharT>
@@ -265,15 +273,35 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
static char_type*
move(char_type* __s1, const char_type* __s2, size_t __n)
- { return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ return static_cast<char_type*>(__builtin___memmove_chk(__s1, __s2, __n,
+ __builtin_object_size (__s1, 0)));
+#else
+ return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
+#endif
+ }
static char_type*
copy(char_type* __s1, const char_type* __s2, size_t __n)
- { return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ return static_cast<char_type*>(__builtin___memcpy_chk(__s1, __s2, __n,
+ __builtin_object_size (__s1, 0)));
+#else
+ return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
+#endif
+ }
static char_type*
assign(char_type* __s, size_t __n, char_type __a)
- { return static_cast<char_type*>(__builtin_memset(__s, __a, __n)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ return static_cast<char_type*>(__builtin___memset_chk(__s, __a, __n, __builtin_object_size (__s, 0)));
+#else
+ return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
+#endif
+ }
static char_type
to_char_type(const int_type& __c)
--- libstdc++-v3/include/bits/valarray_array.h.jj 2007-05-21 16:35:00.000000000 +0200
+++ libstdc++-v3/include/bits/valarray_array.h 2007-09-03 14:32:58.000000000 +0200
@@ -91,7 +91,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
// For fundamental types, it suffices to say 'memset()'
inline static void
_S_do_it(_Tp* __restrict__ __b, _Tp* __restrict__ __e)
- { __builtin_memset(__b, 0, (__e - __b) * sizeof(_Tp)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memset_chk(__b, 0, (__e - __b) * sizeof(_Tp),
+ __builtin_object_size (__b, 0));
+#else
+ __builtin_memset(__b, 0, (__e - __b) * sizeof(_Tp));
+#endif
+ }
};
template<typename _Tp>
@@ -160,7 +167,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
inline static void
_S_do_it(const _Tp* __restrict__ __b, const _Tp* __restrict__ __e,
_Tp* __restrict__ __o)
- { __builtin_memcpy(__o, __b, (__e - __b) * sizeof(_Tp)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__o, __b, (__e - __b) * sizeof(_Tp),
+ __builtin_object_size (__o, 0));
+#else
+ __builtin_memcpy(__o, __b, (__e - __b) * sizeof(_Tp));
+#endif
+ }
};
template<typename _Tp>
@@ -267,7 +281,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{
inline static void
_S_do_it(const _Tp* __restrict__ __a, size_t __n, _Tp* __restrict__ __b)
- { __builtin_memcpy(__b, __a, __n * sizeof (_Tp)); }
+ {
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__b, __a, __n * sizeof(_Tp),
+ __builtin_object_size (__b, 0));
+#else
+ __builtin_memcpy(__b, __a, __n * sizeof (_Tp));
+#endif
+ }
};
// Copy a plain array __a[<__n>] into a play array __b[<>]
--- libstdc++-v3/include/bits/locale_facets.h.jj 2007-05-21 16:35:00.000000000 +0200
+++ libstdc++-v3/include/bits/locale_facets.h 2007-09-03 14:30:11.000000000 +0200
@@ -899,7 +899,11 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{
if (_M_widen_ok == 1)
{
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__to, __lo, __hi - __lo, __builtin_object_size (__to, 0));
+#else
__builtin_memcpy(__to, __lo, __hi - __lo);
+#endif
return __hi;
}
if (!_M_widen_ok)
@@ -964,7 +968,11 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{
if (__builtin_expect(_M_narrow_ok == 1, true))
{
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__to, __lo, __hi - __lo, __builtin_object_size (__to, 0));
+#else
__builtin_memcpy(__to, __lo, __hi - __lo);
+#endif
return __hi;
}
if (!_M_narrow_ok)
@@ -1101,7 +1109,11 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
virtual const char*
do_widen(const char* __lo, const char* __hi, char_type* __dest) const
{
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__dest, __lo, __hi - __lo, __builtin_object_size (__dest, 0));
+#else
__builtin_memcpy(__dest, __lo, __hi - __lo);
+#endif
return __hi;
}
@@ -1154,7 +1166,11 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
do_narrow(const char_type* __lo, const char_type* __hi,
char, char* __dest) const
{
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ __builtin___memcpy_chk(__dest, __lo, __hi - __lo, __builtin_object_size (__dest, 0));
+#else
__builtin_memcpy(__dest, __lo, __hi - __lo);
+#endif
return __hi;
}
--- libstdc++-v3/include/ext/pod_char_traits.h.jj 2007-05-21 16:35:00.000000000 +0200
+++ libstdc++-v3/include/ext/pod_char_traits.h 2007-09-03 14:29:15.000000000 +0200
@@ -140,8 +140,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
static char_type*
move(char_type* __s1, const char_type* __s2, size_t __n)
{
- return static_cast<char_type*>
- (__builtin_memmove(__s1, __s2, __n * sizeof(char_type)));
+#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0
+ return static_cast<char_type*>(__builtin___memmove_chk(__s1, __s2,
+ __n * sizeof(char_type),
+ __builtin_object_size (__s1, 0)));
+#else
+ return static_cast<char_type*>(__builtin_memmove(__s1, __s2,
+ __n * sizeof(char_type)));
+#endif
}
static char_type*
Jakub