From: Jan Kara <jack@suse.cz>
To: Cody P Schafer <cody@linux.vnet.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Jan Kara <jack@suse.cz>,
Andreas Dilger <adilger.kernel@dilger.ca>,
LKML <linux-kernel@vger.kernel.org>,
EXT4 <linux-ext4@vger.kernel.org>
Subject: Re: [PATCH 1/2] rbtree: fix postorder iteration when the rb_node is not the first element in an entry
Date: Tue, 5 Nov 2013 23:56:19 +0100 [thread overview]
Message-ID: <20131105225619.GC9236@quack.suse.cz> (raw)
In-Reply-To: <20131105215755.GB9236@quack.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 2250 bytes --]
On Tue 05-11-13 22:57:55, Jan Kara wrote:
> On Tue 05-11-13 02:05:44, Cody P Schafer wrote:
> > On 11/04/2013 05:40 PM, Cody P Schafer wrote:
> > > Provide a new helper called rb_next_postorder_entry() to perform NULL
> > > checks and container_of() coversions and use it in
> > > rbtree_for_each_entry_safe() to fix oopses that occur when rb_node is
> > > not the first element in the entry.
> >
> > On second thought, it appears I was a bit to hasty with this, and this patch actually breaks things.
> >
> > On 11/04/2013 04:45 PM, Jan Kara wrote:> On Mon 04-11-13 15:26:38, Jan Kara wrote:
> > >> On Fri 01-11-13 15:38:50, Cody P Schafer wrote:
> > >>> Use rbtree_postorder_for_each_entry_safe() to destroy the rbtree instead
> > >>> of opencoding an alternate postorder iteration that modifies the tree
> > >> Thanks. I've merged the patch into my tree.
> > > Hum, except that the kernel oopses with this patch. And I think the
> > > problem is in rbtree_postorder_for_each_entry_safe(). How are those tests
> > > for NULL supposed to work? For example if the tree is empty, 'pos' will be
> > > NULL and you'll call rb_next_postorder(&NULL->field) which is pretty much
> > > guaranteed to oops if 'field' doesn't have offset 0 in the structure...
> >
> > No, it shouldn't oops because pos won't be NULL, &pos->field will be.
> >
> > pos is only assigned via an rb_entry(rb_first_postorder()) or
> > rb_entry(rb_next_postorder()). rb_next_postorder() and
> > rb_first_postorder() can return NULL. That NULL then is munged by
> > rb_entry to be (NULL - offset_of_field). Causing (&pos->field == NULL ==
> > (pos + offset_of_field)).
> OK, so I had a second look. And the compiler thinks differently than you
> :) The thing is that my gcc (4.3.4) apparently assumes pointer underflow is
> undefined and thus optimizes your test &pos->field to 1. I've asked our gcc
> guys for a definitive answer but clearly your code will need some way to
> avoid pointer underflows...
I've just now checked how e.g. hlist iterators solve similar problem and
modified the rbtree iterator accordingly. The patch is attached and with it
and your ext3 patch my test machine is able to boot again.
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
[-- Attachment #2: 0001-rbtree-Fix-rbtree_postorder_for_each_entry_safe-i.patch --]
[-- Type: text/x-patch, Size: 2158 bytes --]
>From d51a16626d241ded8913768d6f24484b1d4335ba Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 5 Nov 2013 21:39:48 +0100
Subject: [PATCH] rbtree: Fix rbtree_postorder_for_each_entry_safe() iterator
The iterator rbtree_postorder_for_each_entry_safe() relies on pointer
underflow behavior when testing for loop termination. In particular
it expects that
&rb_entry(NULL, type, field)->field
is NULL. But the result of this expression is not defined by a C standard
and some gcc versions (e.g. 4.3.4) assume the above expression can never
be equal to NULL. The net result is an oops because the iteration is not
properly terminated.
Fix the problem by modifying the iterator to avoid pointer underflows.
Signed-off-by: Jan Kara <jack@suse.cz>
---
include/linux/rbtree.h | 16 +++++++++-------
1 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index aa870a4..57e75ae 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -85,6 +85,11 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
*rb_link = node;
}
+#define rb_entry_safe(ptr, type, member) \
+ ({ typeof(ptr) ____ptr = (ptr); \
+ ____ptr ? rb_entry(____ptr, type, member) : NULL; \
+ })
+
/**
* rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of
* given type safe against removal of rb_node entry
@@ -95,12 +100,9 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
* @field: the name of the rb_node field within 'type'.
*/
#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \
- for (pos = rb_entry(rb_first_postorder(root), typeof(*pos), field),\
- n = rb_entry(rb_next_postorder(&pos->field), \
- typeof(*pos), field); \
- &pos->field; \
- pos = n, \
- n = rb_entry(rb_next_postorder(&pos->field), \
- typeof(*pos), field))
+ for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \
+ pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \
+ typeof(*pos), field); 1; }); \
+ pos = n)
#endif /* _LINUX_RBTREE_H */
--
1.6.0.2
next prev parent reply other threads:[~2013-11-05 22:56 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1383345566-25087-1-git-send-email-cody@linux.vnet.ibm.com>
2013-11-01 22:38 ` [PATCH 4/8] fs/ext4: use rbtree postorder iteration helper instead of opencoding Cody P Schafer
2013-11-01 22:38 ` [PATCH 6/8] fs/ext3: " Cody P Schafer
2013-11-04 14:26 ` Jan Kara
2013-11-05 0:45 ` Jan Kara
2013-11-05 1:33 ` Cody P Schafer
2013-11-05 1:40 ` [PATCH 1/2] rbtree: fix postorder iteration when the rb_node is not the first element in an entry Cody P Schafer
2013-11-05 1:40 ` [PATCH 2/2] rbtree/test: move rb_node to the middle of the test struct Cody P Schafer
2013-11-05 10:05 ` [PATCH 1/2] rbtree: fix postorder iteration when the rb_node is not the first element in an entry Cody P Schafer
2013-11-05 21:57 ` Jan Kara
2013-11-05 22:56 ` Jan Kara [this message]
2013-11-06 20:18 ` Cody P Schafer
2013-11-06 21:37 ` [PATCH] rbtree/test: test rbtree_postorder_for_each_entry_safe() Cody P Schafer
2013-11-06 23:16 ` Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20131105225619.GC9236@quack.suse.cz \
--to=jack@suse.cz \
--cc=adilger.kernel@dilger.ca \
--cc=akpm@linux-foundation.org \
--cc=cody@linux.vnet.ibm.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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 NNTP newsgroup(s).