diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-12-02 17:14:37 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-02 17:14:37 -0800 |
commit | 8013e0c7bc28e0883363649c94360b4878d1d742 (patch) | |
tree | e9f0d78f6fde2b58cf6f75e191160f773d8d4396 /libbindgen/src | |
parent | 18711e0fc7dd2500df524a7c9f9db4864a8f0c38 (diff) | |
parent | fa5ad81713a738dd181333de3f60a432f22a5003 (diff) |
Auto merge of #314 - fitzgen:assert-no-infinite-loops-in-ancestors, r=emilio
Assert that we won't infinite loop
In non-release builds with debug assertions, keep track of the set of
`ItemId`s that we have iterated over in `ItemAncestorsIter` and make
sure that we don't reach an ancestor we have already yielded, which
would trigger an infinite loop.
Diffstat (limited to 'libbindgen/src')
-rw-r--r-- | libbindgen/src/ir/item.rs | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs index 76ab0d55..f12e4b54 100644 --- a/libbindgen/src/ir/item.rs +++ b/libbindgen/src/ir/item.rs @@ -55,12 +55,45 @@ pub trait ItemAncestors { -> ItemAncestorsIter<'a, 'b>; } +cfg_if! { + if #[cfg(debug_assertions)] { + type DebugOnlyItemSet = ItemSet; + } else { + struct DebugOnlyItemSet; + + impl DebugOnlyItemSet { + fn new() -> Self { + DebugOnlyItemSet + } + + fn contains(&self,_id: &ItemId) -> bool { + false + } + + fn insert(&mut self, _id: ItemId) {} + } + } +} + /// An iterator over an item and its ancestors. pub struct ItemAncestorsIter<'a, 'b> where 'b: 'a, { item: ItemId, ctx: &'a BindgenContext<'b>, + seen: DebugOnlyItemSet, +} + +impl <'a, 'b> ItemAncestorsIter<'a, 'b> + where 'b: 'a +{ + fn new(ctx: &'a BindgenContext<'b>, item: ItemId) -> Self { + ItemAncestorsIter { + item: item, + ctx: ctx, + seen: DebugOnlyItemSet::new(), + } + } } impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b> @@ -70,10 +103,15 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b> fn next(&mut self) -> Option<Self::Item> { let item = self.ctx.resolve_item(self.item); + if item.parent_id() == self.item { None } else { self.item = item.parent_id(); + + debug_assert!(!self.seen.contains(&item.id())); + self.seen.insert(item.id()); + Some(item.id()) } } @@ -100,10 +138,7 @@ impl ItemAncestors for ItemId { fn ancestors<'a, 'b>(&self, ctx: &'a BindgenContext<'b>) -> ItemAncestorsIter<'a, 'b> { - ItemAncestorsIter { - item: *self, - ctx: ctx, - } + ItemAncestorsIter::new(ctx, *self) } } @@ -553,8 +588,13 @@ impl Item { ctx: &BindgenContext, for_name_checking: bool) -> ItemId { + let mut targets_seen = DebugOnlyItemSet::new(); let mut item = self; + loop { + debug_assert!(!targets_seen.contains(&item.id())); + targets_seen.insert(item.id()); + match *item.kind() { ItemKind::Type(ref ty) => { match *ty.kind() { |