* BUG: Using pointer that points to a destructed string's content @ 2014-12-26 11:37 Tamas Szakaly 2014-12-26 22:03 ` David Bremner ` (2 more replies) 0 siblings, 3 replies; 11+ messages in thread From: Tamas Szakaly @ 2014-12-26 11:37 UTC (permalink / raw) To: notmuch -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Dear notmuch developers, The following line is from _notmuch_message_add_directory_terms in lib/message.cc (line 652 in HEAD): direntry = (*i).c_str (); 'i' is a Xapian::TermIterator, whose operator* returns a std::string by value. This means that c_str() is called on a temporary, which is destructed after the full expression (essentially the particular line in this case), so 'direntry' will point to a destructed std::string's data. (See https://gcc.gnu.org/onlinedocs/gcc/Temporaries.html) One possible modification to correct this issue is using strdup: direntry = strdup((*i).c_str ()); Note: Despite the fact that it is wrong, it *generally* works, because delete[]-ing the underlying character array in the destructor of std::string does not really touch the memory content, and there is only a minor chance that this memory area will be allocated again (e.g. from another thread). This caused me some headache though with 'notmuch new' on FreeBSD 11-CURRENT, where jemalloc is configured so that freed memory will be filled with 0x5a's. Best regards, sghctoma - -- -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBAgAGBQJUnUiQAAoJEE8tbNCQOSmESAsH/ih+EFx0WJEzImBkNe4I4H+0 Wj9u/ymmpgLwWnV0rg0oxnYoX5T6zT2e1jwTD73H7N4A2Xf2Susjbr6csTP2YyQB aUbZ5/Ajq+COgpoEXTQUbrIPcIbdl0X05/k9f/OdNqZMHVK6j08hw2oqtpsq6v1+ PiuAa7kKrMda5rzLk08z1/qmJ6D7G2Trl6r5LPfytZhPwrphAJ9bWBofIIJLBQ0R RdeTmGuzc7FBw1a1JqJWkDL1lI91VTD49Wr/VqYXPbfcWbaHhVYSklDshyEYaK/+ skemzV+aIWJiNHpkALdh3t+070caXlv5hwa826Q4kB0FMmkNlShjFqpXLJToEWo= =hshP -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: BUG: Using pointer that points to a destructed string's content 2014-12-26 11:37 BUG: Using pointer that points to a destructed string's content Tamas Szakaly @ 2014-12-26 22:03 ` David Bremner 2014-12-26 23:06 ` Tamas Szakaly 2014-12-27 8:33 ` [PATCH] lib: collapse computation of directory_id into a single expression David Bremner 2015-01-03 13:30 ` BUG: Using pointer that points to a destructed string's content David Bremner 2 siblings, 1 reply; 11+ messages in thread From: David Bremner @ 2014-12-26 22:03 UTC (permalink / raw) To: Tamas Szakaly, notmuch Tamas Szakaly <sghctoma@gmail.com> writes: > The following line is from _notmuch_message_add_directory_terms in > lib/message.cc (line 652 in HEAD): > > direntry = (*i).c_str (); > > 'i' is a Xapian::TermIterator, whose operator* returns a std::string by value. > This means that c_str() is called on a temporary, which is destructed after the > full expression (essentially the particular line in this case), so 'direntry' > will point to a destructed std::string's data. > (See https://gcc.gnu.org/onlinedocs/gcc/Temporaries.html) Does the following patch fix it for you? I have to double check that direntry wasn't needed for something, but the test suite passes ;). diff --git a/lib/message.cc b/lib/message.cc index a7a13cc..24d0d5b 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -649,10 +649,8 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) /* Indicate that there are filenames remaining. */ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - direntry = (*i).c_str (); - direntry += direntry_prefix_len; - - directory_id = strtol (direntry, &colon, 10); + directory_id = strtol ( + (*i).c_str () + direntry_prefix_len, &colon, 10); if (colon == NULL || *colon != ':') INTERNAL_ERROR ("malformed direntry"); ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: BUG: Using pointer that points to a destructed string's content 2014-12-26 22:03 ` David Bremner @ 2014-12-26 23:06 ` Tamas Szakaly 2014-12-28 10:45 ` [PATCH] lib: another iterator-temporary/stale-pointer bug David Bremner 0 siblings, 1 reply; 11+ messages in thread From: Tamas Szakaly @ 2014-12-26 23:06 UTC (permalink / raw) To: notmuch -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 > > The following line is from _notmuch_message_add_directory_terms in > > lib/message.cc (line 652 in HEAD): > > > > direntry = (*i).c_str (); > > > > 'i' is a Xapian::TermIterator, whose operator* returns a std::string by value. > > This means that c_str() is called on a temporary, which is destructed after the > > full expression (essentially the particular line in this case), so 'direntry' > > will point to a destructed std::string's data. > > (See https://gcc.gnu.org/onlinedocs/gcc/Temporaries.html) > > Does the following patch fix it for you? I have to double check that > direntry wasn't needed for something, but the test suite passes ;). > > diff --git a/lib/message.cc b/lib/message.cc > index a7a13cc..24d0d5b 100644 > --- a/lib/message.cc > +++ b/lib/message.cc > @@ -649,10 +649,8 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) > /* Indicate that there are filenames remaining. */ > status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; > > - direntry = (*i).c_str (); > - direntry += direntry_prefix_len; > - > - directory_id = strtol (direntry, &colon, 10); > + directory_id = strtol ( > + (*i).c_str () + direntry_prefix_len, &colon, 10); > > if (colon == NULL || *colon != ':') > INTERNAL_ERROR ("malformed direntry"); > Nope, it's still not correct: with this code "colon" will point into the temporary string's data. I'm using this patch now: - --- work/notmuch-0.18.1/lib/message.cc 2014-06-25 12:30:10.000000000 +0200 +++ /root/message.cc 2014-12-20 08:15:10.000000000 +0100 @@ -601,18 +601,19 @@ unsigned int directory_id; const char *direntry, *directory; char *colon; + const std::string& tmp = *i; + direntry = tmp.c_str (); + /* Terminate loop at first term without desired prefix. */ - - if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len)) + if (strncmp (direntry, direntry_prefix, direntry_prefix_len)) break; /* Indicate that there are filenames remaining. */ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - - direntry = (*i).c_str (); - - direntry += direntry_prefix_len; - - - - directory_id = strtol (direntry, &colon, 10); + directory_id = strtol ( + direntry + direntry_prefix_len, &colon, 10); if (colon == NULL || *colon != ':') INTERNAL_ERROR ("malformed direntry"); This way operator* and c_str will be called only once, and its also better than my first suggestion (using strdup), since it requires no additional memory allocation. Regards, sghctoma - -- -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBAgAGBQJUneoOAAoJEE8tbNCQOSmEzTwH/2NtrBberwi1nPdNgOLm2j9g StrfYLnoIJIjn3dU7/X22QnX7CQHhXDMa+bY7UHDiS+oNTmMfRg0j6t1DV/tA/Pv gA2Ti80zP8B1c0YX/KELGQYcxSQTE/p4hFe0Ff/Yo1Qi4KvFntxBiuvB6I1quQmX 1Kxew2l/Oq2PLOfqtmqfg5GuoDMXiNjNQgmfsV6x+i9F5PR3qnuvrzZvUWCC0URX Xx2w1P+JYBambLdMqOH9MmU4ck/lobCkxprcfUK27i/LSNsl2UH+650bjef3Y6gR CoErHJ4xso9+T8Dk+zRTtK1+uAs66xrLYRverJAnIL3LXFQG+czhUzuAdTaFQCM= =PqvU -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] lib: another iterator-temporary/stale-pointer bug 2014-12-26 23:06 ` Tamas Szakaly @ 2014-12-28 10:45 ` David Bremner 2015-01-01 14:49 ` Jani Nikula 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner 0 siblings, 2 replies; 11+ messages in thread From: David Bremner @ 2014-12-28 10:45 UTC (permalink / raw) To: notmuch Tamas Szakaly points out [1] that the bug fixed in 51b073c still exists in at least one place. This change follows the suggestion of [2] and creates a block scope temporary std::string to avoid the rules of iterators temporaries. [1]: id:20141226113755.GA64154@pamparam [2]: id:20141226230655.GA41992@pamparam --- I decided to take a more minimalist approach than [2]. In particular using "direntry" for two different things seemed slightly trickier than necessary, for no obvious performance gain (calling .c_str() should be cheap). lib/message.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index a7a13cc..bacb4d4 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -641,15 +641,16 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) unsigned int directory_id; const char *direntry, *directory; char *colon; + const std::string term = *i; /* Terminate loop at first term without desired prefix. */ - if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len)) + if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) break; /* Indicate that there are filenames remaining. */ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - direntry = (*i).c_str (); + direntry = term.c_str (); direntry += direntry_prefix_len; directory_id = strtol (direntry, &colon, 10); -- 2.1.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] lib: another iterator-temporary/stale-pointer bug 2014-12-28 10:45 ` [PATCH] lib: another iterator-temporary/stale-pointer bug David Bremner @ 2015-01-01 14:49 ` Jani Nikula 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner 1 sibling, 0 replies; 11+ messages in thread From: Jani Nikula @ 2015-01-01 14:49 UTC (permalink / raw) To: David Bremner, notmuch On Sun, 28 Dec 2014, David Bremner <david@tethera.net> wrote: > Tamas Szakaly points out [1] that the bug fixed in 51b073c still > exists in at least one place. This change follows the suggestion of > [2] and creates a block scope temporary std::string to avoid the rules > of iterators temporaries. > > [1]: id:20141226113755.GA64154@pamparam > [2]: id:20141226230655.GA41992@pamparam > --- > > I decided to take a more minimalist approach than [2]. In particular > using "direntry" for two different things seemed slightly trickier > than necessary, for no obvious performance gain (calling .c_str() > should be cheap). > > lib/message.cc | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/lib/message.cc b/lib/message.cc > index a7a13cc..bacb4d4 100644 > --- a/lib/message.cc > +++ b/lib/message.cc > @@ -641,15 +641,16 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) > unsigned int directory_id; > const char *direntry, *directory; > char *colon; > + const std::string term = *i; You could use a reference here like in [2]. Either way, LGTM. Jani. > > /* Terminate loop at first term without desired prefix. */ > - if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len)) > + if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) > break; > > /* Indicate that there are filenames remaining. */ > status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; > > - direntry = (*i).c_str (); > + direntry = term.c_str (); > direntry += direntry_prefix_len; > > directory_id = strtol (direntry, &colon, 10); > -- > 2.1.3 > > _______________________________________________ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] lib: convert two "iterator copy strings" into references. 2014-12-28 10:45 ` [PATCH] lib: another iterator-temporary/stale-pointer bug David Bremner 2015-01-01 14:49 ` Jani Nikula @ 2015-01-02 16:20 ` David Bremner 2015-01-02 17:52 ` Jani Nikula ` (2 more replies) 1 sibling, 3 replies; 11+ messages in thread From: David Bremner @ 2015-01-02 16:20 UTC (permalink / raw) To: notmuch Apparently this is a supported and even idiomatic way of keeping a temporary object (e.g. like that returned from an operator dereference) alive. --- I decided it was better to do both of these "keepalive" strings the same way, so I applied the parent patch as is. lib/message.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index bacb4d4..956a70a 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -283,7 +283,7 @@ _notmuch_message_get_term (notmuch_message_t *message, if (i == end) return NULL; - std::string term = *i; + const std::string &term = *i; if (strncmp (term.c_str(), prefix, prefix_len)) return NULL; @@ -641,7 +641,7 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) unsigned int directory_id; const char *direntry, *directory; char *colon; - const std::string term = *i; + const std::string &term = *i; /* Terminate loop at first term without desired prefix. */ if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) -- 2.1.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] lib: convert two "iterator copy strings" into references. 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner @ 2015-01-02 17:52 ` Jani Nikula 2015-01-02 20:07 ` Tomi Ollila 2015-01-03 9:03 ` David Bremner 2 siblings, 0 replies; 11+ messages in thread From: Jani Nikula @ 2015-01-02 17:52 UTC (permalink / raw) To: David Bremner, notmuch On Fri, 02 Jan 2015, David Bremner <david@tethera.net> wrote: > Apparently this is a supported and even idiomatic way of keeping a > temporary object (e.g. like that returned from an operator > dereference) alive. > --- > > I decided it was better to do both of these "keepalive" strings the > same way, so I applied the parent patch as is. LGTM. > > lib/message.cc | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/lib/message.cc b/lib/message.cc > index bacb4d4..956a70a 100644 > --- a/lib/message.cc > +++ b/lib/message.cc > @@ -283,7 +283,7 @@ _notmuch_message_get_term (notmuch_message_t *message, > if (i == end) > return NULL; > > - std::string term = *i; > + const std::string &term = *i; > if (strncmp (term.c_str(), prefix, prefix_len)) > return NULL; > > @@ -641,7 +641,7 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) > unsigned int directory_id; > const char *direntry, *directory; > char *colon; > - const std::string term = *i; > + const std::string &term = *i; > > /* Terminate loop at first term without desired prefix. */ > if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) > -- > 2.1.3 > > _______________________________________________ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] lib: convert two "iterator copy strings" into references. 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner 2015-01-02 17:52 ` Jani Nikula @ 2015-01-02 20:07 ` Tomi Ollila 2015-01-03 9:03 ` David Bremner 2 siblings, 0 replies; 11+ messages in thread From: Tomi Ollila @ 2015-01-02 20:07 UTC (permalink / raw) To: David Bremner, notmuch On Fri, Jan 02 2015, David Bremner <david@tethera.net> wrote: > Apparently this is a supported and even idiomatic way of keeping a > temporary object (e.g. like that returned from an operator > dereference) alive. > --- Based on internet search with words 'c++ reference to temporary' (*) I believe the change is working one. Tomi (*) Uh, reading those explations gives me a headache >;) > > I decided it was better to do both of these "keepalive" strings the > same way, so I applied the parent patch as is. > > lib/message.cc | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/lib/message.cc b/lib/message.cc > index bacb4d4..956a70a 100644 > --- a/lib/message.cc > +++ b/lib/message.cc > @@ -283,7 +283,7 @@ _notmuch_message_get_term (notmuch_message_t *message, > if (i == end) > return NULL; > > - std::string term = *i; > + const std::string &term = *i; > if (strncmp (term.c_str(), prefix, prefix_len)) > return NULL; > > @@ -641,7 +641,7 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) > unsigned int directory_id; > const char *direntry, *directory; > char *colon; > - const std::string term = *i; > + const std::string &term = *i; > > /* Terminate loop at first term without desired prefix. */ > if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) > -- > 2.1.3 > > _______________________________________________ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] lib: convert two "iterator copy strings" into references. 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner 2015-01-02 17:52 ` Jani Nikula 2015-01-02 20:07 ` Tomi Ollila @ 2015-01-03 9:03 ` David Bremner 2 siblings, 0 replies; 11+ messages in thread From: David Bremner @ 2015-01-03 9:03 UTC (permalink / raw) To: notmuch David Bremner <david@tethera.net> writes: > Apparently this is a supported and even idiomatic way of keeping a > temporary object (e.g. like that returned from an operator > dereference) alive. pushed. d ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] lib: collapse computation of directory_id into a single expression 2014-12-26 11:37 BUG: Using pointer that points to a destructed string's content Tamas Szakaly 2014-12-26 22:03 ` David Bremner @ 2014-12-27 8:33 ` David Bremner 2015-01-03 13:30 ` BUG: Using pointer that points to a destructed string's content David Bremner 2 siblings, 0 replies; 11+ messages in thread From: David Bremner @ 2014-12-27 8:33 UTC (permalink / raw) To: notmuch According to id:20141226113755.GA64154@pamparam , the lifetime of (*i).c_str is only guaranteed for that line, so we extract the information we need in the same line. --- lib/message.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index a7a13cc..14e60af 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -639,7 +639,7 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) for (i.skip_to (direntry_prefix); i != message->doc.termlist_end (); i++) { unsigned int directory_id; - const char *direntry, *directory; + const char *directory; char *colon; /* Terminate loop at first term without desired prefix. */ @@ -649,10 +649,9 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) /* Indicate that there are filenames remaining. */ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - direntry = (*i).c_str (); - direntry += direntry_prefix_len; - - directory_id = strtol (direntry, &colon, 10); + directory_id = + strtol ((*i).c_str () + direntry_prefix_len, + &colon, 10); if (colon == NULL || *colon != ':') INTERNAL_ERROR ("malformed direntry"); -- 2.1.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: BUG: Using pointer that points to a destructed string's content 2014-12-26 11:37 BUG: Using pointer that points to a destructed string's content Tamas Szakaly 2014-12-26 22:03 ` David Bremner 2014-12-27 8:33 ` [PATCH] lib: collapse computation of directory_id into a single expression David Bremner @ 2015-01-03 13:30 ` David Bremner 2 siblings, 0 replies; 11+ messages in thread From: David Bremner @ 2015-01-03 13:30 UTC (permalink / raw) To: Tamas Szakaly, notmuch Tamas Szakaly <sghctoma@gmail.com> writes: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Dear notmuch developers, > > The following line is from _notmuch_message_add_directory_terms in > lib/message.cc (line 652 in HEAD): > > direntry = (*i).c_str (); > This should be fixed in commit 3d978a0d d ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-01-03 13:30 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-12-26 11:37 BUG: Using pointer that points to a destructed string's content Tamas Szakaly 2014-12-26 22:03 ` David Bremner 2014-12-26 23:06 ` Tamas Szakaly 2014-12-28 10:45 ` [PATCH] lib: another iterator-temporary/stale-pointer bug David Bremner 2015-01-01 14:49 ` Jani Nikula 2015-01-02 16:20 ` [PATCH] lib: convert two "iterator copy strings" into references David Bremner 2015-01-02 17:52 ` Jani Nikula 2015-01-02 20:07 ` Tomi Ollila 2015-01-03 9:03 ` David Bremner 2014-12-27 8:33 ` [PATCH] lib: collapse computation of directory_id into a single expression David Bremner 2015-01-03 13:30 ` BUG: Using pointer that points to a destructed string's content David Bremner
Code repositories for project(s) associated with this public inbox https://yhetil.org/notmuch.git/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).