unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* 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: 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

* [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

* 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).