[Aptitude-devel] r3231 - in branches/aptitude-0.3/aptitude: . src/generic/problemresolver

Daniel Burrows dburrows@costa.debian.org
Sun, 01 May 2005 15:39:16 +0000


Author: dburrows
Date: Sun May  1 15:39:13 2005
New Revision: 3231

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
Log:
Fix a crash in the test code.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Sun May  1 15:39:13 2005
@@ -1,5 +1,14 @@
 2005-05-01  Daniel Burrows  <dburrows@debian.org>
 
+	* src/generic/problemresolver/test.cc:
+
+	  Fix a crash that occured when an error was encountered in
+	  parsing a test file: the resolver copied the universe, which had
+	  references to the package objects, and hence the packages got
+	  double-deleted.  Now universes are reference-counted and it's
+	  the references that are copied around, so the problem should go
+	  away.
+
 	* src/generic/problemresolver/problemresolver.h:
 
 	  When dumping version scores, actually write the scores instead

Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc	Sun May  1 15:39:13 2005
@@ -682,7 +682,120 @@
   }
 };
 
-typedef generic_problem_resolver<dummy_universe> dummy_resolver;
+// A refcounting wrapper for a dummy_universe; used to sanitize memory
+// management without copying all over (and because the resolver
+// expects to be able to have a full copy of its argument type)
+class dummy_universe_ref
+{
+  struct _rep
+  {
+    int refcount;
+    dummy_universe *universe;
+
+    /** Start with 1 ref since our creator holds a ref. */
+    _rep(dummy_universe *_universe)
+      :refcount(1), universe(_universe)
+    {
+    }
+
+    void incref() {++refcount;}
+    void decref() {--refcount; if(refcount==0) delete this;}
+  };
+
+  _rep *rep;
+public:
+  typedef dummy_universe::package package;
+  typedef dummy_universe::version version;
+  typedef dummy_universe::dep dep;
+  typedef dummy_universe::package_iterator package_iterator;
+  typedef dummy_universe::dep_iterator dep_iterator;
+  typedef dummy_universe::broken_dep_iterator broken_dep_iterator;
+
+  dummy_universe_ref()
+    :rep(NULL)
+  {
+  }
+
+  dummy_universe_ref(const dummy_universe_ref &other)
+    :rep(other.rep)
+  {
+  }
+
+  /** Assumes this is the first reference to the universe. */
+  dummy_universe_ref(dummy_universe *universe)
+    :rep(new _rep(universe))
+  {
+  }
+
+  ~dummy_universe_ref()
+  {
+    if(rep)
+      rep->decref();
+  }
+
+  dummy_universe_ref &operator=(const dummy_universe_ref &other)
+  {
+    if(other.rep)
+      other.rep->incref();
+    if(rep)
+      rep->decref();
+    rep=other.rep;
+
+    return *this;
+  }
+
+  operator void*() const
+  {
+    return (void *) (rep && rep->universe);
+  }
+
+  void add_package(string name,
+		   vector<string> the_versions,
+		   string curname) const
+  {
+    rep->universe->add_package(name, the_versions, curname);
+  }
+
+  void add_dep(string pkg_name, string pkg_ver,
+	       const vector<pair<string, string> > &target_names,
+	       bool is_conflict)
+  {
+    rep->universe->add_dep(pkg_name, pkg_ver,
+			   target_names, is_conflict);
+  }
+
+  package find_package(string pkg_name) const
+  {
+    return rep->universe->find_package(pkg_name);
+  }
+
+  vector<package>::size_type get_package_count() const
+  {
+    return rep->universe->get_package_count();
+  }
+
+  vector<version>::size_type get_version_count() const
+  {
+    return rep->universe->get_version_count();
+  }
+
+  package_iterator packages_begin() const
+  {
+    return rep->universe->packages_begin();
+  }
+
+  dep_iterator deps_begin() const
+  {
+    return rep->universe->deps_begin();
+  }
+
+  broken_dep_iterator broken_begin() const
+  {
+    return rep->universe->broken_begin();
+  }
+};
+
+typedef generic_problem_resolver<dummy_universe_ref> dummy_resolver;
 
 ostream &operator<<(ostream &out, const dummy_resolver::dep &d)
 {
@@ -743,9 +856,9 @@
 }
 
 /** Parses a universe to the closing ']'. */
-dummy_universe *parse_universe(istream &in)
+dummy_universe_ref parse_universe(istream &in)
 {
-  dummy_universe *rval=new dummy_universe;
+  dummy_universe_ref rval=new dummy_universe;
 
   in >> ws;
   while(in)
@@ -803,7 +916,7 @@
 	  if(vernames.empty())
 	    throw ParseError("Package "+pkgname+" has no versions");
 
-	  rval->add_package(pkgname, vernames, curname);
+	  rval.add_package(pkgname, vernames, curname);
 	}
       else if(s == "DEP")
 	{
@@ -853,8 +966,8 @@
 		throw ParseError("Unexpected EOF in dependency target list following package "+pkgname+" version "+vername);
 	    }
 
-	  rval->add_dep(source.first, source.second, targets,
-			is_conflict);
+	  rval.add_dep(source.first, source.second, targets,
+		       is_conflict);
 	}
       else
 	throw ParseError("Expected PACKAGE or DEP, got "+s);
@@ -868,7 +981,7 @@
 
 /** Reads the list of scores into the resolver. */
 void read_scores(istream &f,
-		 dummy_universe *universe, dummy_resolver &resolver)
+		 dummy_universe_ref universe, dummy_resolver &resolver)
 {
   if(!universe)
     throw ParseError("Internal error: NULL universe in read_scores");
@@ -892,7 +1005,7 @@
 
 	  f >> pkgname >> ws;
 
-	  dummy_universe::package pkg=universe->find_package(pkgname);
+	  dummy_universe::package pkg=universe.find_package(pkgname);
 
 	  if(f.eof())
 	    throw ParseError("Expected '<' following package name, got EOF");
@@ -942,7 +1055,7 @@
 }
 
 /** Reads the tail of a non-ANY SOLN form. */
-map<dummy_universe::package, dummy_resolver::version> read_solution(istream &f, dummy_universe *universe)
+map<dummy_universe::package, dummy_resolver::version> read_solution(istream &f, dummy_universe_ref universe)
 {
   if(!universe)
     throw ParseError("Internal error: NULL universe passed to read_solution");
@@ -967,7 +1080,7 @@
 	  if(f.eof())
 	    throw ParseError("Expected version, got EOF");
 
-	  dummy_universe::package pkg=universe->find_package(s);
+	  dummy_universe::package pkg=universe.find_package(s);
 
 	  f >> s >> ws;
 
@@ -991,7 +1104,7 @@
 
 void run_test_file(istream &f)
 {
-  dummy_universe *universe=NULL;
+  dummy_universe_ref universe=NULL;
 
   f >> ws;
 
@@ -1017,13 +1130,10 @@
 	      if(s != "[")
 		throw ParseError("Expected '[' following UNIVERSE, got " + s);
 
-	      dummy_universe *new_universe=parse_universe(f);
-
-	      delete universe;
-	      universe=new_universe;
+	      universe=parse_universe(f);
 
 	      cout << "Input universe:" << endl;
-	      dump_universe(*universe, cout);
+	      dump_universe(universe, cout);
 	    }
 	  else if(s == "TEST")
 	    {
@@ -1054,7 +1164,7 @@
 
 	      dummy_resolver resolver(step_score, broken_score,
 				      infinity, max_successors,
-				      goal_score, *universe);
+				      goal_score, universe);
 
 	      read_scores(f, universe, resolver);
 
@@ -1170,7 +1280,6 @@
     }
   catch(...)
     {
-      delete universe;
       throw;
     }
 }