Thread: Valgrind Memcheck support

Valgrind Memcheck support

From
Noah Misch
Date:
Valgrind's Memcheck tool[1] is handy for finding bugs, but our use of a custom
allocator limits its ability to detect problems in unmodified PostgreSQL.
During the 9.1 beta cycle, I found some bugs[2] with a rough patch adding
instrumentation to aset.c and mcxt.c such that Memcheck understood our
allocator.  I've passed that patch around to a few people over time, and I've
now removed the roughness such that it's ready for upstream.  In hopes of
making things clearer in the commit history, I've split out a preliminary
refactoring patch from the main patch and attached each separately.

Besides the aset.c/mcxt.c instrumentation, this patch adds explicit checks for
undefined memory to PageAddItem() and printtup(); this has caught C-language
functions that fabricate a Datum without initializing all bits.  The inclusion
of all this is controlled by a pg_config_manual.h setting.  The patch also
adds a "suppression file" that directs Valgrind to silences nominal errors we
don't plan to fix.

To smoke-test the instrumentation, I used "make installcheck" runs on x86_64
GNU/Linux and ppc64 GNU/Linux.  This turned up various new and newly-detected
memory bugs, which I will discuss in a separate thread.  With those fixed,
"make installcheck" has a clean report (in my one particular configuration).
I designed the suppression file to work across platforms; I specifically
anticipated eventual use on x86_64 Darwin and x86_64 FreeBSD.  Valgrind 3.8.1
quickly crashed when running PostgreSQL on Darwin; I did not dig further.

Since aset.c and mcxt.c contain the hottest code paths in the backend, I
verified that a !USE_VALGRIND, non-assert build produces the same code before
and after the patch.  Testing that revealed the need to move up the
AllocSizeIsValid() check in repalloc(), though I don't understand why GCC
reacted that way.

Peter Geoghegan and Korry Douglas provided valuable feedback on earlier
versions of this code.


Possible future directions:

- Test "make installcheck-world".  When I last did this in past years, contrib did
  trigger some errors.

- Test recovery, such as by running a streaming replica under Memcheck while
  the primary runs "make installcheck-world".

- Test newer compilers and higher optimization levels.  I used GCC 4.2 at -O1.
  A brief look at -O2 results showed a new error that I have not studied.  GCC
  4.8 at -O3 might show still more due to increasingly-aggressive assumptions.

- A buildfarm member running its installcheck steps this way.

- Memcheck has support for detecting leaks.  I have not explored that side at
  all, always passing --leak-check=no.  We could add support for freeing
  "everything" at process exit, thereby making the leak detection meaningful.


Brief notes for folks reproducing my approach: I typically start the
Memcheck-hosted postgres like this:

  valgrind --leak-check=no --gen-suppressions=all \
    --suppressions=src/tools/valgrind.supp --time-stamp=yes \
    --log-file=$HOME/pg-valgrind/%p.log postgres

If that detected an error on which I desired more detail, I would rerun a
smaller test case with "--track-origins=yes --read-var-info=yes".  That slows
things noticeably but gives more-specific messaging.  When even that left the
situation unclear, I would temporarily hack allocChunkLimit so every palloc()
turned into a malloc().

I strongly advise installing the latest-available Valgrind, particularly
because recent releases suffer far less of a performance drop processing the
instrumentation added by this patch.  A "make installcheck" run takes 273
minutes under Vaglrind 3.6.0 but just 27 minutes under Valgrind 3.8.1.

Thanks,
nm

[1] http://valgrind.org/docs/manual/mc-manual.html
[2] http://www.postgresql.org/message-id/20110312133224.GA7833@tornado.gateway.2wire.net

--
Noah Misch
EnterpriseDB                                 http://www.enterprisedb.com

Attachment

Re: Valgrind Memcheck support

From
Andres Freund
Date:
On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
> Valgrind's Memcheck tool[1] is handy for finding bugs, but our use of a custom
> allocator limits its ability to detect problems in unmodified PostgreSQL.
> During the 9.1 beta cycle, I found some bugs[2] with a rough patch adding
> instrumentation to aset.c and mcxt.c such that Memcheck understood our
> allocator.  I've passed that patch around to a few people over time, and I've
> now removed the roughness such that it's ready for upstream.  In hopes of
> making things clearer in the commit history, I've split out a preliminary
> refactoring patch from the main patch and attached each separately.

> Besides the aset.c/mcxt.c instrumentation, this patch adds explicit checks for
> undefined memory to PageAddItem() and printtup(); this has caught C-language
> functions that fabricate a Datum without initializing all bits.  The inclusion
> of all this is controlled by a pg_config_manual.h setting.  The patch also
> adds a "suppression file" that directs Valgrind to silences nominal errors we
> don't plan to fix.

Very nice work. I've started to do this quite some time back to smoke
out some bugs in code of mine, but never got remotely to a point where
it was submittable. But I already found some bugs with it. So I'd very
happy if this could get committed.

Will take a look.

> I strongly advise installing the latest-available Valgrind, particularly
> because recent releases suffer far less of a performance drop processing the
> instrumentation added by this patch.  A "make installcheck" run takes 273
> minutes under Vaglrind 3.6.0 but just 27 minutes under Valgrind 3.8.1.

At least on linux amd64 I'd strongly suggest using something newer than
(afair) 3.8.1, i.e. the svn version. Up to that version it corrupts the
stack alignment inside signal handlers which doesn't get fixed up even
after a fork(). This leads to mysterious segfaults, e.g. during elog()s
due to the usage of sse registers which have stronger alignment
requirements.

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Valgrind Memcheck support

From
Andres Freund
Date:
Hi Noah,

On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
> *** a/src/backend/tcop/postgres.c
> --- b/src/backend/tcop/postgres.c
> ***************
> *** 69,74 ****
> --- 69,75 ----
>   #include "tcop/tcopprot.h"
>   #include "tcop/utility.h"
>   #include "utils/lsyscache.h"
> + #include "utils/memdebug.h"
>   #include "utils/memutils.h"
>   #include "utils/ps_status.h"
>   #include "utils/snapmgr.h"
> ***************
> *** 846,851 **** exec_simple_query(const char *query_string)
> --- 847,856 ----
>   
>       TRACE_POSTGRESQL_QUERY_START(query_string);
>   
> + #ifdef USE_VALGRIND
> +     VALGRIND_PRINTF("statement: %s\n", query_string);
> + #endif
> + 

Is there a special reason for adding more logging here? I find this
makes the instrumentation much less useful since reports easily get
burried in those traces. What's the advantage of doing this instead of
log_statement=...? Especially as that location afaics won't help for the
extended protocol?

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Valgrind Memcheck support

From
Atri Sharma
Date:

Sent from my iPad

On 27-Aug-2013, at 19:44, Andres Freund <andres@2ndquadrant.com> wrote:

> Hi Noah,
>
> On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
>> *** a/src/backend/tcop/postgres.c
>> --- b/src/backend/tcop/postgres.c
>> ***************
>> *** 69,74 ****
>> --- 69,75 ----
>>  #include "tcop/tcopprot.h"
>>  #include "tcop/utility.h"
>>  #include "utils/lsyscache.h"
>> + #include "utils/memdebug.h"
>>  #include "utils/memutils.h"
>>  #include "utils/ps_status.h"
>>  #include "utils/snapmgr.h"
>> ***************
>> *** 846,851 **** exec_simple_query(const char *query_string)
>> --- 847,856 ----
>>
>>      TRACE_POSTGRESQL_QUERY_START(query_string);
>>
>> + #ifdef USE_VALGRIND
>> +    VALGRIND_PRINTF("statement: %s\n", query_string);
>> + #endif
>> +
>
> Is there a special reason for adding more logging here? I find this
> makes the instrumentation much less useful since reports easily get
> burried in those traces. What's the advantage of doing this instead of
> log_statement=...? Especially as that location afaics won't help for the
> extended protocol?
>
>

+1. I also feel that extra traces may tend to confuse up the actual hot spot. Extra debugging can be happily be done
withhigher log levels. 

Regards,

Atri


Re: Valgrind Memcheck support

From
Noah Misch
Date:
On Tue, Aug 27, 2013 at 04:14:27PM +0200, Andres Freund wrote:
> On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
> > ***************
> > *** 846,851 **** exec_simple_query(const char *query_string)
> > --- 847,856 ----
> >   
> >       TRACE_POSTGRESQL_QUERY_START(query_string);
> >   
> > + #ifdef USE_VALGRIND
> > +     VALGRIND_PRINTF("statement: %s\n", query_string);
> > + #endif
> > + 
> 
> Is there a special reason for adding more logging here? I find this
> makes the instrumentation much less useful since reports easily get
> burried in those traces. What's the advantage of doing this instead of
> log_statement=...? Especially as that location afaics won't help for the
> extended protocol?

I typically used "valgrind --log-file=...".  To determine via log_statement
which SQL statement caused a particular Valgrind error, I would match by
timestamp; this was easier.  In retrospect, log_statement would have sufficed
given both Valgrind and PostgreSQL logging to stderr.  Emitting the message in
exec_simple_query() and not in exec_execute_message() is indeed indefensible.

That being said, could you tell me more about your workflow where the extra
messages cause a problem?  Do you just typically diagnose each Valgrind error
without first isolating the pertinent SQL statement?

Thanks,
nm

-- 
Noah Misch
EnterpriseDB                                 http://www.enterprisedb.com



Re: Valgrind Memcheck support

From
Andres Freund
Date:
On 2013-08-27 23:46:23 -0400, Noah Misch wrote:
> On Tue, Aug 27, 2013 at 04:14:27PM +0200, Andres Freund wrote:
> > On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
> > > ***************
> > > *** 846,851 **** exec_simple_query(const char *query_string)
> > > --- 847,856 ----
> > >   
> > >       TRACE_POSTGRESQL_QUERY_START(query_string);
> > >   
> > > + #ifdef USE_VALGRIND
> > > +     VALGRIND_PRINTF("statement: %s\n", query_string);
> > > + #endif
> > > + 
> > 
> > Is there a special reason for adding more logging here? I find this
> > makes the instrumentation much less useful since reports easily get
> > burried in those traces. What's the advantage of doing this instead of
> > log_statement=...? Especially as that location afaics won't help for the
> > extended protocol?
> 
> I typically used "valgrind --log-file=...".  To determine via log_statement
> which SQL statement caused a particular Valgrind error, I would match by
> timestamp; this was easier.  In retrospect, log_statement would have sufficed
> given both Valgrind and PostgreSQL logging to stderr.  Emitting the message in
> exec_simple_query() and not in exec_execute_message() is indeed indefensible.

It's an understandable mistake, nothing indefensible. We don't really
test the extended protocol :(

> That being said, could you tell me more about your workflow where the extra
> messages cause a problem?  Do you just typically diagnose each Valgrind error
> without first isolating the pertinent SQL statement?

There's basically two scenarios where I found it annoying:
a) I manually reproduce some issue, potentially involving several psql
shells. All those fire up autocompletion and such queries which bloat
the log while I actually only want to analyze something specific.
b) I don't actually look for anything triggered by an SQL statement
itself, but am looking for issues in a walsender, background worker,
whatever. I still need some foreground activity to trigger the behaviour
I want to see, but once more, valgrind's logs hide the error.

Also, I sometimes use valgrind's --db-command/--vgdb which gives you
enough context from the backtrace itself since you can just get the
statement from there.

I vote for just removing that VALGRIND_PRINTF - it doesn't give you
anything you cannot easily achieve otherwise...

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Valgrind Memcheck support

From
Noah Misch
Date:
On Wed, Aug 28, 2013 at 03:16:14PM +0200, Andres Freund wrote:
> On 2013-08-27 23:46:23 -0400, Noah Misch wrote:
> > On Tue, Aug 27, 2013 at 04:14:27PM +0200, Andres Freund wrote:
> > > On 2013-06-09 17:25:59 -0400, Noah Misch wrote:
> > > > ***************
> > > > *** 846,851 **** exec_simple_query(const char *query_string)
> > > > --- 847,856 ----
> > > >   
> > > >       TRACE_POSTGRESQL_QUERY_START(query_string);
> > > >   
> > > > + #ifdef USE_VALGRIND
> > > > +     VALGRIND_PRINTF("statement: %s\n", query_string);
> > > > + #endif
> > > > + 
> > > 
> > > Is there a special reason for adding more logging here? I find this
> > > makes the instrumentation much less useful since reports easily get
> > > burried in those traces. What's the advantage of doing this instead of
> > > log_statement=...? Especially as that location afaics won't help for the
> > > extended protocol?

> > That being said, could you tell me more about your workflow where the extra
> > messages cause a problem?  Do you just typically diagnose each Valgrind error
> > without first isolating the pertinent SQL statement?
> 
> There's basically two scenarios where I found it annoying:
> a) I manually reproduce some issue, potentially involving several psql
> shells. All those fire up autocompletion and such queries which bloat
> the log while I actually only want to analyze something specific.
> b) I don't actually look for anything triggered by an SQL statement
> itself, but am looking for issues in a walsender, background worker,
> whatever. I still need some foreground activity to trigger the behaviour
> I want to see, but once more, valgrind's logs hide the error.
> 
> Also, I sometimes use valgrind's --db-command/--vgdb which gives you
> enough context from the backtrace itself since you can just get the
> statement from there.

Gotcha.  My largest use case was running "make installcheck" in search of
longstanding bugs.  The runs were unattended, and associating each Valgrind
error with its proximate command was a basic need.

> I vote for just removing that VALGRIND_PRINTF - it doesn't give you
> anything you cannot easily achieve otherwise...

I'd like to see a buildfarm member running "make installcheck" under Valgrind,
so I'd like the code to fit the needs thereof without patching beyond
pg_config_manual.h.  Perhaps having the buildfarm member do "valgrind postgres
--log-statement=all 2>combined-logfile" is good enough.

-- 
Noah Misch
EnterpriseDB                                 http://www.enterprisedb.com



Re: Valgrind Memcheck support

From
Greg Stark
Date:

On Sun, Jun 9, 2013 at 10:25 PM, Noah Misch <noah@leadboat.com> wrote:
- Test recovery, such as by running a streaming replica under Memcheck while
  the primary runs "make installcheck-world".

In general we need a lot more testing on the recovery code.
 
- Memcheck has support for detecting leaks.  I have not explored that side at
  all, always passing --leak-check=no.  We could add support for freeing
  "everything" at process exit, thereby making the leak detection meaningful.

I think this is missing the type of leaks we actually care about. The way palloc works we can be virtually certain that if we did that we wouldn't have any leaks. All it would detect are the random one-off mallocs we know very well are there.

The problems we've had with leaks in the past are invariably things allocated at the "wrong" memory context. Things that can grow for every row processed but are stored per-query or for every query processed but stored per-sesson. To detect that will requires more of a heuristic where when a child memory context is reset any parent context growth is logged.

--
greg

Re: Valgrind Memcheck support

From
Noah Misch
Date:
On Wed, Aug 28, 2013 at 10:30:34PM -0400, Noah Misch wrote:
> On Wed, Aug 28, 2013 at 03:16:14PM +0200, Andres Freund wrote:
> > I vote for just removing that VALGRIND_PRINTF - it doesn't give you
> > anything you cannot easily achieve otherwise...

Done.

> I'd like to see a buildfarm member running "make installcheck" under Valgrind,
> so I'd like the code to fit the needs thereof without patching beyond
> pg_config_manual.h.  Perhaps having the buildfarm member do "valgrind postgres
> --log-statement=all 2>combined-logfile" is good enough.

-- 
Noah Misch
EnterpriseDB                                 http://www.enterprisedb.com



Re: Valgrind Memcheck support

From
Noah Misch
Date:
On Fri, Sep 06, 2013 at 09:55:09PM +0100, Greg Stark wrote:
> On Sun, Jun 9, 2013 at 10:25 PM, Noah Misch <noah@leadboat.com> wrote:
> >  - Memcheck has support for detecting leaks.  I have not explored that
> > side at
> >   all, always passing --leak-check=no.  We could add support for freeing
> >   "everything" at process exit, thereby making the leak detection
> > meaningful.
> >
> 
> I think this is missing the type of leaks we actually care about. The way
> palloc works we can be virtually certain that if we did that we wouldn't
> have any leaks. All it would detect are the random one-off mallocs we know
> very well are there.

Probably so; it's not too promising.

-- 
Noah Misch
EnterpriseDB                                 http://www.enterprisedb.com



Re: Valgrind Memcheck support

From
Andres Freund
Date:
On 2013-09-06 21:55:09 +0100, Greg Stark wrote:
> On Sun, Jun 9, 2013 at 10:25 PM, Noah Misch <noah@leadboat.com> wrote:
> 
> > - Test recovery, such as by running a streaming replica under Memcheck
> > while
> >   the primary runs "make installcheck-world".
> >
> 
> In general we need a lot more testing on the recovery code.
> 
> 
> >  - Memcheck has support for detecting leaks.  I have not explored that
> > side at
> >   all, always passing --leak-check=no.  We could add support for freeing
> >   "everything" at process exit, thereby making the leak detection
> > meaningful.
> >
> 
> I think this is missing the type of leaks we actually care about. The way
> palloc works we can be virtually certain that if we did that we wouldn't
> have any leaks. All it would detect are the random one-off mallocs we know
> very well are there.

Well, we do have a good number of things that allocate stuff in
TopMemoryContext. So it might already catch leaks into that. IIRC we
don't reset that, but even if, that can easily be removed.
Valgrind's detection for "unreachable memory" is nice for that.

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services