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 46632 4cdebce7020a1a7142845773278f78e9512240fc
parent 46631 2e5f92d640fe1e9201117fba2aef245984dc360e
child 46633 95990e1a50e5647fc6c3b3dcc73ca92c518f8251
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscjones
milestone1.9.3a1pre
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
@@ -941,16 +941,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:
@@ -974,16 +994,23 @@ class CheckTypes(TcheckVisitor):
         if not p.decl.type.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))
 
         return Visitor.visitProtocol(self, p)
         
 
     def visitManagesStmt(self, mgs):
         pdecl = mgs.manager.decl
         ptype, pname = pdecl.type, pdecl.shortname
 
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__();
+};
+