diff options
Diffstat (limited to 'gcc/ggc-common.c')
-rw-r--r-- | gcc/ggc-common.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index db7cece5e2d..007bf4666cf 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -31,6 +31,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA # include <sys/mman.h> #endif +#ifdef ENABLE_VALGRIND_CHECKING +#include <valgrind.h> +#else +/* Avoid #ifdef:s when we can help it. */ +#define VALGRIND_DISCARD(x) +#endif + /* Statistics about the allocation. */ static ggc_statistics *ggc_stats; @@ -123,10 +130,36 @@ ggc_realloc (x, size) old_size = ggc_get_size (x); if (size <= old_size) - return x; + { + /* Mark the unwanted memory as unaccessible. We also need to make + the "new" size accessible, since ggc_get_size returns the size of + the pool, not the size of the individually allocated object, the + size which was previously made accessible. Unfortunately, we + don't know that previously allocated size. Without that + knowledge we have to lose some initialization-tracking for the + old parts of the object. An alternative is to mark the whole + old_size as reachable, but that would lose tracking of writes + after the end of the object (by small offsets). Discard the + handle to avoid handle leak. */ + VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size, + old_size - size)); + VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size)); + return x; + } r = ggc_alloc (size); + + /* Since ggc_get_size returns the size of the pool, not the size of the + individually allocated object, we'd access parts of the old object + that were marked invalid with the memcpy below. We lose a bit of the + initialization-tracking since some of it may be uninitialized. */ + VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size)); + memcpy (r, x, old_size); + + /* The old object is not supposed to be used anymore. */ + VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x, old_size)); + return r; } |