Sfoglia il codice sorgente

invalid cache if architecture set doesn't match

The cache heavily depends on the architecture(s) it is build for,
especially if you move from single- to multiarch. Adding a new
architecture to dpkg therefore has to be detected and must invalidate
the cache so that we don't operate on incorrect data.

The incorrect data will prevent us from doing otherwise sensible
actions (it doesn't allow bad things to happen) and the recovery is
simple and automatic in most cases, so this hides pretty well and is
also not as serious as it might sound at first.

Closes: 745036
David Kalnischkies 12 anni fa
parent
commit
7a223b933c

+ 1 - 1
apt-pkg/aptconfiguration.cc

@@ -540,7 +540,7 @@ std::string const Configuration::getBuildProfilesString() {
 		return "";
 	std::vector<std::string>::const_iterator p = profiles.begin();
 	std::string list = *p;
-	for (; p != profiles.end(); ++p)
+	for (++p; p != profiles.end(); ++p)
 	   list.append(",").append(*p);
 	return list;
 }

+ 14 - 6
apt-pkg/pkgcache.cc

@@ -168,15 +168,23 @@ bool pkgCache::ReMap(bool const &Errorchecks)
    if (Map.Size() < HeaderP->CacheFileSize)
       return _error->Error(_("The package cache file is corrupted, it is too small"));
 
+   if (HeaderP->VerSysName == 0 || HeaderP->Architecture == 0 || HeaderP->Architectures == 0)
+      return _error->Error(_("The package cache file is corrupted"));
+
    // Locate our VS..
-   if (HeaderP->VerSysName == 0 ||
-       (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
+   if ((VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
       return _error->Error(_("This APT does not support the versioning system '%s'"),StrP + HeaderP->VerSysName);
 
-   // Chcek the arhcitecture
-   if (HeaderP->Architecture == 0 ||
-       _config->Find("APT::Architecture") != StrP + HeaderP->Architecture)
-      return _error->Error(_("The package cache was built for a different architecture"));
+   // Check the architecture
+   std::vector<std::string> archs = APT::Configuration::getArchitectures();
+   std::vector<std::string>::const_iterator a = archs.begin();
+   std::string list = *a;
+   for (++a; a != archs.end(); ++a)
+      list.append(",").append(*a);
+   if (_config->Find("APT::Architecture") != StrP + HeaderP->Architecture ||
+	 list != StrP + HeaderP->Architectures)
+      return _error->Error(_("The package cache was built for different architectures: %s vs %s"), StrP + HeaderP->Architectures, list.c_str());
+
    return true;
 }
 									/*}}}*/

+ 3 - 1
apt-pkg/pkgcache.h

@@ -286,8 +286,10 @@ struct pkgCache::Header
    map_ptrloc StringList;
    /** \brief String representing the version system used */
    map_ptrloc VerSysName;
-   /** \brief Architecture(s) the cache was built against */
+   /** \brief native architecture the cache was built against */
    map_ptrloc Architecture;
+   /** \brief all architectures the cache was built against */
+   map_ptrloc Architectures;
    /** \brief The maximum size of a raw entry from the original Package file */
    unsigned long MaxVerFileSize;
    /** \brief The maximum size of a raw entry from the original Translation file */

+ 20 - 2
apt-pkg/pkgcachegen.cc

@@ -74,13 +74,31 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
       // Starting header
       *Cache.HeaderP = pkgCache::Header();
       map_ptrloc const idxVerSysName = WriteStringInMap(_system->VS->Label);
+      if (unlikely(idxVerSysName == 0))
+	 return;
       Cache.HeaderP->VerSysName = idxVerSysName;
       // this pointer is set in ReMap, but we need it now for WriteUniqString
       Cache.StringItemP = (pkgCache::StringItem *)Map.Data();
       map_ptrloc const idxArchitecture = WriteUniqString(_config->Find("APT::Architecture"));
-      Cache.HeaderP->Architecture = idxArchitecture;
-      if (unlikely(idxVerSysName == 0 || idxArchitecture == 0))
+      if (unlikely(idxArchitecture == 0))
 	 return;
+      Cache.HeaderP->Architecture = idxArchitecture;
+
+      std::vector<std::string> archs = APT::Configuration::getArchitectures();
+      if (archs.size() > 1)
+      {
+	 std::vector<std::string>::const_iterator a = archs.begin();
+	 std::string list = *a;
+	 for (++a; a != archs.end(); ++a)
+	    list.append(",").append(*a);
+	 map_ptrloc const idxArchitectures = WriteStringInMap(list);
+	 if (unlikely(idxArchitectures == 0))
+	    return;
+	 Cache.HeaderP->Architectures = idxArchitectures;
+      }
+      else
+	 Cache.HeaderP->Architectures = idxArchitecture;
+
       Cache.ReMap();
    }
    else

+ 29 - 0
test/integration/test-bug-745036-new-foreign-invalidates-cache

@@ -0,0 +1,29 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'amd64'
+
+insertpackage 'unstable' 'cool-foo' 'amd64' '1.0' 'Depends: foo'
+insertpackage 'unstable' 'foo' 'amd64' '1.0' 'Multi-Arch: foreign'
+insertinstalledpackage 'cool-foo' 'amd64' '1.0' 'Depends: foo'
+insertinstalledpackage 'foo' 'amd64' '1.0' 'Multi-Arch: foreign'
+
+setupaptarchive
+
+testsuccess aptget check -s
+
+configarchitecture 'amd64' 'i386'
+testequal 'E: The package cache was built for different architectures: amd64 vs amd64,i386' aptget check -s -o pkgCacheFile::Generate=false
+
+testsuccess aptget check -s
+
+insertinstalledpackage 'awesome-foo' 'i386' '1.0' 'Depends: foo'
+
+testsuccess aptget check -s
+
+testsuccess aptget update --no-download
+
+testsuccess aptget check -s