Bug 541126: Error out if there are manager/managee cycles in protocol graphs. r=cjones
authorThomas Lee <bugzilla@deskchecked.com.au>
Mon, 01 Feb 2010 12:44:54 -0600
changeset 41429 4f4a912c36f0c3bec0064c423967aca9c8b4e7d3
parent 41428 3bd0a0a9d8b18683df8707753a1c3cc34ba505ea
child 41430 7ad3e029c695fd7198c7aaaa3f26010a9e2e4d8d
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs541126
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 541126: Error out if there are manager/managee cycles in protocol graphs. r=cjones
ipc/ipdl/ipdl/type.py
ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -946,16 +946,36 @@ class GatherDecls(TcheckVisitor):
         if typespec.array:
             itype = ArrayType(itype)
 
         return itype
 
 
 ##-----------------------------------------------------------------------------
 
+def checkcycles(p, stack=None):
+    cycles = []
+
+    if stack is None:
+        stack = []
+
+    for cp in p.manages:
+        if cp in stack:
+            return [stack + [p, cp]]
+        cycles += checkcycles(cp, stack + [p])
+
+    return cycles
+
+def formatcycles(cycles):
+    r = []
+    for cycle in cycles:
+        s = " -> ".join([ptype.name() for ptype in cycle])
+        r.append("`%s'" % s)
+    return ", ".join(r)
+
 class CheckTypes(TcheckVisitor):
     def __init__(self, errors):
         # don't need the symbol table, we just want the error reporting
         TcheckVisitor.__init__(self, None, errors)
         self.visited = set()
 
     def visitProtocolInclude(self, inc):
         if inc.tu.filename in self.visited:
@@ -979,16 +999,23 @@ class CheckTypes(TcheckVisitor):
         if not ptype.isToplevel():
             for md in p.messageDecls:
                 if _DELETE_MSG == md.name: break
             else:
                 self.error(
                     p.decl.loc,
                    "managed protocol `%s' requires a `delete()' message to be declared",
                     p.name)
+        else:
+            cycles = checkcycles(p.decl.type)
+            if cycles:
+                self.error(
+                    p.decl.loc,
+                    "cycle(s) detected in manager/manages heirarchy: %s",
+                    formatcycles(cycles))
 
         if 1 == len(ptype.managers) and ptype is ptype.manager():
             self.error(
                 p.decl.loc,
                 "top-level protocol `%s' cannot manage itself",
                 p.name)
 
         return Visitor.visitProtocol(self, p)
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
@@ -0,0 +1,12 @@
+include protocol "cyclecheck_Parent.ipdl";
+include protocol "cyclecheck_Grandchild.ipdl";
+
+protocol cyclecheck_Child {
+    manager cyclecheck_Parent;
+    manages cyclecheck_Grandchild;
+
+child:
+    cyclecheck_Grandchild();
+    __delete__();
+};
+
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
@@ -0,0 +1,12 @@
+include protocol "cyclecheck_Child.ipdl";
+include protocol "cyclecheck_Parent.ipdl";
+
+protocol cyclecheck_Grandchild {
+    manager cyclecheck_Child;
+    manages cyclecheck_Parent;
+
+child:
+    cyclecheck_Parent();
+    __delete__();
+};
+
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
@@ -0,0 +1,10 @@
+include protocol "cyclecheck_Child.ipdl";
+
+protocol cyclecheck_Parent {
+    manages cyclecheck_Child;
+
+child:
+    cyclecheck_Child();
+    __delete__();
+};
+