From: Ivan Zakharyaschev <imz@altlinux.org> To: ALT Linux Team development discussions <devel@lists.altlinux.org> Cc: Anton Farygin <rider@altlinux.org>, "Vladimir D. Seleznev" <vseleznv@altlinux.org> Subject: Re: [devel] [SCM] packages/apt: heads/rework-dynamic-mmap Date: Tue, 11 Feb 2020 16:47:41 +0300 (MSK) Message-ID: <alpine.LFD.2.20.2002111638550.6363@imap.altlinux.org> (raw) In-Reply-To: <6acb6b5b-d135-7071-f500-3142170aefda@altlinux.org> [-- Attachment #1: Type: text/plain, Size: 39198 bytes --] Hello! On Thu, 30 Jan 2020, Aleksei Nikiforov wrote: > > Чтобы не было удивления от бессмысленного значения, я переписал так, как > > ты увидел. Не люблю операции, которые какой-то мусор присваивают, просто > > чтобы место чем-то заполнить. > > > > В моём варианте Prv даже не конструируется и не начинает заполняться, если > > не удалось выделить память в Map под строку Version. Это же понятнее и > > лишних вопросов не вызвает: что потом с этой частично осмысленно > > заполненной, частично незаполненной структурой произойдёт и кто её в таком > > виде увидит дальше. > > > > По сути установление нуля - это лишь сохранение старого поведения. Если вызов > WriteString(Version) возвращал ноль, то сначала этот ноль присваивался > Prv->ProvideVersion, а уже затем проверялось значение Prv->ProvideVersion. С > новым API в случае ошибки возвращается особое значение, пустой > std::experimental::optional, но для сохранения старого поведения данной > функции pkgCacheGenerator::ListParser::NewProvides ноль присваивается > переменной Prv->ProvideVersion. Я не счёл необходимым сильнее менять данную > функцию, по крайней мере до сих пор, но если есть желание дальше изменять > данный код - я не возражаю. Теперь в своей ветке optional учёл это высказанное соображение и прочие мелкие замечания, которые тут высказывались к моим редакциям этих изменений в виде коммитов. В этом месте сначала делаю ближе к старому поведению, потом в другом коммите меняю сильнее. Теперь вся серия выглядит так: $ git --no-pager log -p base..optional commit 9146fbb5ccf224505334190472fe7ddfc1531e4e Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Mon Feb 10 13:03:07 2020 +0300 .dir-locals.el: apply our Emacs mode settings to .h files, too diff --git a/apt/.dir-locals.el b/apt/.dir-locals.el index c1497844e..acc107299 100644 --- a/apt/.dir-locals.el +++ b/apt/.dir-locals.el @@ -2,4 +2,9 @@ ;;; For more information see (info "(emacs) Directory Variables") ((c++-mode + (c-basic-offset . 3)) + + ;; For switching in .h headers: + (c-mode + (mode . c++) (c-basic-offset . 3))) commit f9de67b18e05656ec43df41cde61dbb338fd01f4 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Mon Feb 10 17:02:20 2020 +0300 DynamicMMap::RawAllocate(): do not modify data on failure diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc index ef9e31242..d387560e8 100644 --- a/apt/apt-pkg/contrib/mmap.cc +++ b/apt/apt-pkg/contrib/mmap.cc @@ -207,9 +207,7 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) unsigned long long Result = iSize; if (Aln != 0) Result += Aln - (iSize%Aln); - - iSize = Result + Size; - + // Just in case error check if (Result + Size > WorkSpace) { @@ -217,6 +215,8 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) return 0; } + iSize = Result + Size; + return Result; } /*}}}*/ commit 5fa3ac151d7b5290a775e69f7e79dce0837db2d8 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Mon Feb 10 17:03:42 2020 +0300 DynamicMMap::RawAllocate(): no offset needed if already aligned (was off-by-one) diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc index d387560e8..44cc6bae4 100644 --- a/apt/apt-pkg/contrib/mmap.cc +++ b/apt/apt-pkg/contrib/mmap.cc @@ -206,7 +206,7 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) { unsigned long long Result = iSize; if (Aln != 0) - Result += Aln - (iSize%Aln); + Result += Aln - (iSize%Aln ? : Aln); // Just in case error check if (Result + Size > WorkSpace) commit ca6142850ccea2f726bb59295f16fe5a0820a562 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Mon Feb 10 19:29:34 2020 +0300 DynamicMMap::WriteString(): fix the check for "out of room" when length is automatic It made no sense to make the check before we have the valid value in Len. diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc index 44cc6bae4..6b56775a1 100644 --- a/apt/apt-pkg/contrib/mmap.cc +++ b/apt/apt-pkg/contrib/mmap.cc @@ -271,6 +271,9 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) unsigned long DynamicMMap::WriteString(const char *String, unsigned long Len) { + if (Len == (unsigned long)-1) + Len = strlen(String); + unsigned long Result = iSize; // Just in case error check if (Result + Len > WorkSpace) @@ -279,8 +282,6 @@ unsigned long DynamicMMap::WriteString(const char *String, return 0; } - if (Len == (unsigned long)-1) - Len = strlen(String); iSize += Len + 1; memcpy((char *)Base + Result,String,Len); ((char *)Base)[Result + Len] = 0; commit e785f0e8636e47a672445e70f2923a5eea566b33 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Wed Jan 29 04:41:13 2020 +0300 use the safer C++-style static_cast instead of a C-style cast (from void*) What is happening here: Map->RawAllocate() returns the index in an array of bytes (i.e., of char; no matter whether they are (un)signed); therefore, we cast the base pointer to the corresponding type, so that the pointer arithmetic gives a pointer to the beginning of the allocated space. We do not want to rely on non-standard void*-arithmetic. diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc index 070c0f040..16d3592e9 100644 --- a/apt/apt-pkg/pkgcachegen.cc +++ b/apt/apt-pkg/pkgcachegen.cc @@ -882,7 +882,7 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, { // Preload the map with the source cache FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly); - if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()), + if (SCacheF.Read(static_cast<char *>(Map->Data()) + Map->RawAllocate(SCacheF.Size()), SCacheF.Size()) == false) return false; commit 4d297001f6d3ddc3e12cf4b950e821d867b77092 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Wed Jan 29 05:02:13 2020 +0300 rigorously compute HeaderP as the pointer to the beginning of Map The old code expected that the first call to Map.RawAllocate() would give the pointer to the very beginning of Map, i.e., the same as Map.Data(). We rewrite this code without such presupposition: no matter what the logic behind Map.RawAllocate() will ever be, we'll actually get the pointer to the space which is being "allocated" by this call inside Map. We use the safer C++-style static_cast (from void*) where possible. What is happening here with the pointer arithmetic: Map->RawAllocate() returns the index in an array of bytes (i.e., of char); therefore, we cast the base pointer to the corresponding type, so that the pointer arithmetic gives the correct pointer to the beginning of the "allocated" space. We do not want to rely on non-standard void*-arithmetic. diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc index 16d3592e9..8bf5ed639 100644 --- a/apt/apt-pkg/pkgcachegen.cc +++ b/apt/apt-pkg/pkgcachegen.cc @@ -54,9 +54,10 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : if (Map.Size() == 0) { + const auto idxBeginning = Map.RawAllocate(sizeof(pkgCache::Header)); + // Setup the map interface.. - Cache.HeaderP = (pkgCache::Header *)Map.Data(); - Map.RawAllocate(sizeof(pkgCache::Header)); + Cache.HeaderP = reinterpret_cast<pkgCache::Header *>(static_cast<char *>(Map.Data()) + idxBeginning); Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); // Starting header commit 063c9051ddc8d736193733f19ab9a821c30ce3b8 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Wed Jan 29 20:41:33 2020 +0300 Use special type to return allocation failure since 0 is a valid offset value This change is heavily based on: commit 667677a7d268aaf0f84ce3bc0567c5350db20ec6 Author: Aleksei Nikiforov <darktemplar@altlinux.org> Date: Thu Jun 13 12:35:49 2019 +0300 Use special type to return allocation failure since 0 is a valid offset value which has been rebased and purified a bit (so that the code clearly matches the intention at the changed places). Co-Authored-by: Vladimir D. Seleznev <vseleznv@altlinux.org>. diff --git a/apt.spec b/apt.spec index 362179ec1..4b18a9453 100644 --- a/apt.spec +++ b/apt.spec @@ -230,7 +230,7 @@ printf '%_target_cpu\t%_target_cpu' >> buildlib/archtable %autoreconf %add_optflags -DAPTRPM_ID=\\\"%name-%{?epoch:%epoch:}%version-%release%{?disttag::%disttag}.%_target_cpu\\\" %ifarch %e2k -%add_optflags -std=gnu++11 +%add_optflags -std=c++14 %endif %configure --includedir=%_includedir/apt-pkg %{subst_enable static} diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc index 6b56775a1..77aad3656 100644 --- a/apt/apt-pkg/contrib/mmap.cc +++ b/apt/apt-pkg/contrib/mmap.cc @@ -202,7 +202,7 @@ DynamicMMap::~DynamicMMap() // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/ // --------------------------------------------------------------------- /* This allocates a block of memory aligned to the given size */ -unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) +std::experimental::optional<unsigned long> DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) { unsigned long long Result = iSize; if (Aln != 0) @@ -212,7 +212,7 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) if (Result + Size > WorkSpace) { _error->Error("Dynamic MMap ran out of room"); - return 0; + return std::experimental::nullopt; } iSize = Result + Size; @@ -224,8 +224,8 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) // --------------------------------------------------------------------- /* This allocates an Item of size ItemSize so that it is aligned to its size in the file. */ -unsigned long DynamicMMap::Allocate(unsigned long ItemSize) -{ +std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize) +{ // Look for a matching pool entry Pool *I; Pool *Empty = 0; @@ -244,7 +244,7 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) if (Empty == 0) { _error->Error("Ran out of allocation pools"); - return 0; + return std::experimental::nullopt; } I = Empty; @@ -256,8 +256,14 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) if (I->Count == 0) { I->Count = 20*1024/ItemSize; - I->Start = RawAllocate(I->Count*ItemSize,ItemSize); - } + auto idxResult = RawAllocate(I->Count*ItemSize,ItemSize); + + // Has the allocation failed? + if (!idxResult) + return idxResult; + + I->Start = *idxResult; + } I->Count--; unsigned long Result = I->Start; @@ -268,7 +274,7 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) // DynamicMMap::WriteString - Write a string to the file /*{{{*/ // --------------------------------------------------------------------- /* Strings are not aligned to anything */ -unsigned long DynamicMMap::WriteString(const char *String, +std::experimental::optional<unsigned long> DynamicMMap::WriteString(const char *String, unsigned long Len) { if (Len == (unsigned long)-1) @@ -279,7 +285,7 @@ unsigned long DynamicMMap::WriteString(const char *String, if (Result + Len > WorkSpace) { _error->Error("Dynamic MMap ran out of room"); - return 0; + return std::experimental::nullopt; } iSize += Len + 1; diff --git a/apt/apt-pkg/contrib/mmap.h b/apt/apt-pkg/contrib/mmap.h index efc5245cb..14df0550c 100644 --- a/apt/apt-pkg/contrib/mmap.h +++ b/apt/apt-pkg/contrib/mmap.h @@ -29,6 +29,7 @@ #endif #include <string> +#include <experimental/optional> #include <apt-pkg/fileutl.h> using std::string; @@ -90,10 +91,10 @@ class DynamicMMap : public MMap public: // Allocation - unsigned long RawAllocate(unsigned long Size,unsigned long Aln = 0); - unsigned long Allocate(unsigned long ItemSize); - unsigned long WriteString(const char *String,unsigned long Len = (unsigned long)-1); - inline unsigned long WriteString(const string &S) {return WriteString(S.c_str(),S.length());}; + std::experimental::optional<unsigned long> RawAllocate(unsigned long Size,unsigned long Aln = 0); + std::experimental::optional<unsigned long> Allocate(unsigned long ItemSize); + std::experimental::optional<unsigned long> WriteString(const char *String,unsigned long Len = (unsigned long)-1); + inline std::experimental::optional<unsigned long> WriteString(const string &S) {return WriteString(S.c_str(),S.length());}; void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;}; DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace = 2*1024*1024); diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc index 8bf5ed639..4c6055cbb 100644 --- a/apt/apt-pkg/pkgcachegen.cc +++ b/apt/apt-pkg/pkgcachegen.cc @@ -55,16 +55,20 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : if (Map.Size() == 0) { const auto idxBeginning = Map.RawAllocate(sizeof(pkgCache::Header)); + const auto idxVerSysName = WriteStringInMap(_system->VS->Label); + const auto idxArch = WriteStringInMap(_config->Find("APT::Architecture")); + if ((!idxBeginning) || (!idxVerSysName) || (!idxArch)) + return; // Setup the map interface.. - Cache.HeaderP = reinterpret_cast<pkgCache::Header *>(static_cast<char *>(Map.Data()) + idxBeginning); + Cache.HeaderP = reinterpret_cast<pkgCache::Header *>(static_cast<char *>(Map.Data()) + *idxBeginning); Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); // Starting header *Cache.HeaderP = pkgCache::Header(); - Cache.HeaderP->VerSysName = WriteStringInMap(_system->VS->Label); - Cache.HeaderP->Architecture = WriteStringInMap(_config->Find("APT::Architecture")); - Cache.ReMap(); + Cache.HeaderP->VerSysName = *idxVerSysName; + Cache.HeaderP->Architecture = *idxArch; + Cache.ReMap(); } else { @@ -98,17 +102,17 @@ pkgCacheGenerator::~pkgCacheGenerator() } /*}}}*/ // CacheGenerator::WriteStringInMap /*{{{*/ -unsigned long pkgCacheGenerator::WriteStringInMap(const char *String, +std::experimental::optional<unsigned long> pkgCacheGenerator::WriteStringInMap(const char *String, unsigned long Len) { return Map.WriteString(String, Len); } /*}}}*/ // CacheGenerator::WriteStringInMap /*{{{*/ -unsigned long pkgCacheGenerator::WriteStringInMap(const char *String) { +std::experimental::optional<unsigned long> pkgCacheGenerator::WriteStringInMap(const char *String) { return Map.WriteString(String); } /*}}}*/ -unsigned long pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/ +std::experimental::optional<unsigned long> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/ return Map.Allocate(size); } /*}}}*/ @@ -222,7 +226,12 @@ bool pkgCacheGenerator::MergeList(ListParser &List, } // Add a new version - *Last = NewVersion(Ver,Version,*Last); + const auto verindex = NewVersion(Ver,Version,*Last); + if (!verindex) + return _error->Error(_("Error occurred while processing %s (NewVersion0)"), + PackageName.c_str()); + *Last = *verindex; + Ver->ParentPkg = Pkg.Index(); Ver->Hash = Hash; if (List.NewVersion(Ver) == false) @@ -366,21 +375,20 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg, const string &Nam #endif // Get a structure - unsigned long Package = AllocateInMap(sizeof(pkgCache::Package)); - if (Package == 0) + const auto Package = AllocateInMap(sizeof(pkgCache::Package)); + const auto idxName = WriteStringInMap(Name); + if ((!Package) || (!idxName)) return false; - - Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package); - + + Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + *Package); + // Insert it into the hash table unsigned long Hash = Cache.Hash(Name); Pkg->NextPackage = Cache.HeaderP->HashTable[Hash]; - Cache.HeaderP->HashTable[Hash] = Package; - + Cache.HeaderP->HashTable[Hash] = *Package; + // Set the name and the ID - Pkg->Name = WriteStringInMap(Name); - if (Pkg->Name == 0) - return false; + Pkg->Name = *idxName; Pkg->ID = Cache.HeaderP->PackageCount++; return true; @@ -408,7 +416,11 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver, if ( (':' - '@' < 0 ? rc < 0 : rc > 0) || (rc != 0 && List.IsDatabase()) ) { - Ver->VerStr = WriteStringInMap(Version); + const auto verStrIdx = WriteStringInMap(Version); + if (!verStrIdx) + return false; + + Ver->VerStr = *verStrIdx; } } @@ -416,11 +428,11 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver, return true; // Get a structure - unsigned long VerFile = AllocateInMap(sizeof(pkgCache::VerFile)); - if (VerFile == 0) - return 0; + const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile)); + if (!VerFile) + return false; - pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile); + pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + *VerFile); VF->File = CurrentFile - Cache.PkgFileP; // Link it to the end of the list @@ -442,23 +454,22 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver, // CacheGenerator::NewVersion - Create a new Version /*{{{*/ // --------------------------------------------------------------------- /* This puts a version structure in the linked list */ -unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, +std::experimental::optional<unsigned long> pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, const string &VerStr, unsigned long Next) { // Get a structure - unsigned long Version = AllocateInMap(sizeof(pkgCache::Version)); - if (Version == 0) - return 0; - + const auto Version = AllocateInMap(sizeof(pkgCache::Version)); + const auto idxVerStr = WriteStringInMap(VerStr); + if ((!Version) || (!idxVerStr)) + return std::experimental::nullopt; + // Fill it in - Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version); + Ver = pkgCache::VerIterator(Cache,Cache.VerP + *Version); Ver->NextVer = Next; Ver->ID = Cache.HeaderP->VersionCount++; - Ver->VerStr = WriteStringInMap(VerStr); - if (Ver->VerStr == 0) - return 0; - + Ver->VerStr = *idxVerStr; + return Version; } /*}}}*/ @@ -475,12 +486,12 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver, pkgCache &Cache = Owner->Cache; // Get a structure - unsigned long Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency)); - if (Dependency == 0) + const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency)); + if (!Dependency) return false; // Fill it in - pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency); + pkgCache::DepIterator Dep(Cache,Cache.DepP + *Dependency); Dep->ParentVer = Ver.Index(); Dep->Type = Type; Dep->CompareOp = Op; @@ -498,8 +509,13 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver, if (I->Version != 0 && I.TargetVer() == Version) Dep->Version = I->Version;*/ if (Dep->Version == 0) - if ((Dep->Version = WriteString(Version)) == 0) - return false; + { + const auto index = WriteString(Version); + if (!index) + return false; + + Dep->Version = *index; + } } // Link it to the package @@ -545,18 +561,29 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, #endif // Get a structure - unsigned long Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); - if (Provides == 0) + const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); + if (!Provides) return false; Cache.HeaderP->ProvidesCount++; // Fill it in - pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP); + pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + *Provides,Cache.PkgP); Prv->Version = Ver.Index(); Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); - if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0) - return false; + + if (Version.empty() == false) + { + const auto idxVersion = WriteString(Version); + // FIXME: If this allocation fails, did it make sense to fill in Prv above? + if (!idxVersion) + { + // FIXME: Does it really make sense to fill it in on failure? + Prv->ProvideVersion = 0; + return false; + } + Prv->ProvideVersion = *idxVersion; + } // Locate the target package pkgCache::PkgIterator Pkg; @@ -580,23 +607,24 @@ bool pkgCacheGenerator::SelectFile(const string &File, const string &Site, unsigned long Flags) { // Get some space for the structure - CurrentFile = Cache.PkgFileP + AllocateInMap(sizeof(*CurrentFile)); - if (CurrentFile == Cache.PkgFileP) + const auto idxFile = AllocateInMap(sizeof(*CurrentFile)); + const auto idxFileName = WriteStringInMap(File); + const auto idxSite = WriteUniqString(Site); + const auto idxIndexType = WriteUniqString(Index.GetType()->Label); + if ((!idxFile) || (!idxFileName) || (!idxSite) || (!idxIndexType)) return false; + CurrentFile = Cache.PkgFileP + *idxFile; // Fill it in - CurrentFile->FileName = WriteStringInMap(File); - CurrentFile->Site = WriteUniqString(Site); + CurrentFile->FileName = *idxFileName; + CurrentFile->Site = *idxSite; CurrentFile->NextFile = Cache.HeaderP->FileList; CurrentFile->Flags = Flags; CurrentFile->ID = Cache.HeaderP->PackageFileCount; - CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label); + CurrentFile->IndexType = *idxIndexType; PkgFileName = File; Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP; Cache.HeaderP->PackageFileCount++; - - if (CurrentFile->FileName == 0) - return false; if (Progress != 0) Progress->SubProgress(Index.Size()); @@ -607,7 +635,7 @@ bool pkgCacheGenerator::SelectFile(const string &File, const string &Site, // --------------------------------------------------------------------- /* This is used to create handles to strings. Given the same text it always returns the same number */ -unsigned long pkgCacheGenerator::WriteUniqString(const char *S, +std::experimental::optional<unsigned long> pkgCacheGenerator::WriteUniqString(const char *S, unsigned int Size) { /* We use a very small transient hash table here, this speeds up generation @@ -637,18 +665,17 @@ unsigned long pkgCacheGenerator::WriteUniqString(const char *S, } // Get a structure - unsigned long Item = AllocateInMap(sizeof(pkgCache::StringItem)); - if (Item == 0) - return 0; + const auto Item = AllocateInMap(sizeof(pkgCache::StringItem)); + const auto idxString = WriteStringInMap(S, Size); + if ((!Item) || (!idxString)) + return std::experimental::nullopt; // Fill in the structure - pkgCache::StringItem *ItemP = Cache.StringItemP + Item; + pkgCache::StringItem *ItemP = Cache.StringItemP + *Item; ItemP->NextItem = I - Cache.StringItemP; - *Last = Item; - ItemP->String = WriteStringInMap(S,Size); - if (ItemP->String == 0) - return 0; - + *Last = *Item; + ItemP->String = *idxString; + Bucket = ItemP; return ItemP->String; } @@ -883,7 +910,10 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, { // Preload the map with the source cache FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly); - if (SCacheF.Read(static_cast<char *>(Map->Data()) + Map->RawAllocate(SCacheF.Size()), + const auto idxAllocate = Map->RawAllocate(SCacheF.Size()); + if (!idxAllocate) + return false; + if (SCacheF.Read(static_cast<char *>(Map->Data()) + *idxAllocate, SCacheF.Size()) == false) return false; diff --git a/apt/apt-pkg/pkgcachegen.h b/apt/apt-pkg/pkgcachegen.h index a187cd1e8..69c4f2ea1 100644 --- a/apt/apt-pkg/pkgcachegen.h +++ b/apt/apt-pkg/pkgcachegen.h @@ -24,6 +24,8 @@ #include <apt-pkg/pkgcache.h> +#include <experimental/optional> + class pkgSourceList; class OpProgress; class MMap; @@ -34,10 +36,10 @@ class pkgCacheGenerator private: pkgCache::StringItem *UniqHash[26]; - unsigned long WriteStringInMap(const std::string &String) { return WriteStringInMap(String.c_str(), String.length()); }; - unsigned long WriteStringInMap(const char *String); - unsigned long WriteStringInMap(const char *String, unsigned long Len); - unsigned long AllocateInMap(unsigned long size); + std::experimental::optional<unsigned long> WriteStringInMap(const std::string &String) { return WriteStringInMap(String.c_str(), String.length()); }; + std::experimental::optional<unsigned long> WriteStringInMap(const char *String); + std::experimental::optional<unsigned long> WriteStringInMap(const char *String, unsigned long Len); + std::experimental::optional<unsigned long> AllocateInMap(unsigned long size); public: @@ -57,15 +59,15 @@ class pkgCacheGenerator bool FoundFileDeps; bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List); - unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next); + std::experimental::optional<unsigned long> NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next); public: // CNC:2003-02-27 - We need this in rpmListParser. bool NewPackage(pkgCache::PkgIterator &PkgI,const string &Pkg); - unsigned long WriteUniqString(const char *S,unsigned int Size); - inline unsigned long WriteUniqString(const string &S) {return WriteUniqString(S.c_str(),S.length());}; + std::experimental::optional<unsigned long> WriteUniqString(const char *S,unsigned int Size); + inline std::experimental::optional<unsigned long> WriteUniqString(const string &S) {return WriteUniqString(S.c_str(),S.length());}; void DropProgress() {Progress = 0;}; bool SelectFile(const string &File,const string &Site,pkgIndexFile const &Index, @@ -101,10 +103,10 @@ class pkgCacheGenerator::ListParser pkgCacheGenerator *Owner; friend class pkgCacheGenerator; - inline unsigned long WriteUniqString(const string &S) {return Owner->WriteUniqString(S);}; - inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);}; - inline unsigned long WriteString(const string &S) {return Owner->WriteStringInMap(S);}; - inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->WriteStringInMap(S,Size);}; + inline std::experimental::optional<unsigned long> WriteUniqString(const string &S) {return Owner->WriteUniqString(S);}; + inline std::experimental::optional<unsigned long> WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);}; + inline std::experimental::optional<unsigned long> WriteString(const string &S) {return Owner->WriteStringInMap(S);}; + inline std::experimental::optional<unsigned long> WriteString(const char *S,unsigned int Size) {return Owner->WriteStringInMap(S,Size);}; bool NewDepends(pkgCache::VerIterator &Ver, const string &Package, const string &Version,unsigned int Op, unsigned int Type); diff --git a/apt/apt-pkg/rpm/rpmlistparser.cc b/apt/apt-pkg/rpm/rpmlistparser.cc index 2fc4e01b8..b3d18d7e6 100644 --- a/apt/apt-pkg/rpm/rpmlistparser.cc +++ b/apt/apt-pkg/rpm/rpmlistparser.cc @@ -70,7 +70,7 @@ rpmListParser::~rpmListParser() // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/ // --------------------------------------------------------------------- /* */ -unsigned long rpmListParser::UniqFindTagWrite(int Tag) +std::experimental::optional<unsigned long> rpmListParser::UniqFindTagWrite(int Tag) { char *Start; char *Stop; @@ -79,7 +79,7 @@ unsigned long rpmListParser::UniqFindTagWrite(int Tag) void *data; if (headerGetEntry(header, Tag, &type, &data, &count) != 1) - return 0; + return std::experimental::nullopt; if (type == RPM_STRING_TYPE) { @@ -255,8 +255,13 @@ bool rpmListParser::NewVersion(pkgCache::VerIterator &Ver) #endif // Parse the section - Ver->Section = UniqFindTagWrite(RPMTAG_GROUP); - Ver->Arch = UniqFindTagWrite(RPMTAG_ARCH); + const auto idxSection = UniqFindTagWrite(RPMTAG_GROUP); + const auto idxArch = UniqFindTagWrite(RPMTAG_ARCH); + if ((!idxSection) || (!idxArch)) + return false; + + Ver->Section = *idxSection; + Ver->Arch = *idxArch; // Archive Size Ver->Size = Handler->FileSize(); @@ -296,7 +301,14 @@ bool rpmListParser::UsePackage(pkgCache::PkgIterator &Pkg, if (SeenPackages != NULL) (*SeenPackages)[Pkg.Name()] = true; if (Pkg->Section == 0) - Pkg->Section = UniqFindTagWrite(RPMTAG_GROUP); + { + const auto idxSection = UniqFindTagWrite(RPMTAG_GROUP); + if (!idxSection) + return false; + + Pkg->Section = *idxSection; + } + if (_error->PendingError()) return false; string PkgName = Pkg.Name(); @@ -740,19 +752,61 @@ bool rpmListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI, const char *Start; const char *Stop; + if (Section.Find("Archive",Start,Stop)) - FileI->Archive = WriteUniqString(Start,Stop - Start); + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Archive = *idx; + } + if (Section.Find("Component",Start,Stop)) - FileI->Component = WriteUniqString(Start,Stop - Start); + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Component = *idx; + } + if (Section.Find("Version",Start,Stop)) - FileI->Version = WriteUniqString(Start,Stop - Start); + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Version = *idx; + } + if (Section.Find("Origin",Start,Stop)) - FileI->Origin = WriteUniqString(Start,Stop - Start); + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Origin = *idx; + } + if (Section.Find("Label",Start,Stop)) - FileI->Label = WriteUniqString(Start,Stop - Start); + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Label = *idx; + } + if (Section.Find("Architecture",Start,Stop)) - FileI->Architecture = WriteUniqString(Start,Stop - Start); - + { + const auto idx = WriteUniqString(Start, Stop - Start); + if (!idx) + return false; + + FileI->Architecture = *idx; + } + if (Section.FindFlag("NotAutomatic",FileI->Flags, pkgCache::Flag::NotAutomatic) == false) _error->Warning(_("Bad NotAutomatic flag")); diff --git a/apt/apt-pkg/rpm/rpmlistparser.h b/apt/apt-pkg/rpm/rpmlistparser.h index 5c6173c0a..dd57f7c9b 100644 --- a/apt/apt-pkg/rpm/rpmlistparser.h +++ b/apt/apt-pkg/rpm/rpmlistparser.h @@ -20,6 +20,7 @@ #include <map> #include <vector> #include <regex.h> +#include <experimental/optional> using namespace std; @@ -45,7 +46,7 @@ class rpmListParser : public pkgCacheGenerator::ListParser bool Duplicated; - unsigned long UniqFindTagWrite(int Tag); + std::experimental::optional<unsigned long> UniqFindTagWrite(int Tag); bool ParseStatus(pkgCache::PkgIterator &Pkg,pkgCache::VerIterator &Ver); bool ParseDepends(pkgCache::VerIterator &Ver, char **namel, char **verl, int32_t *flagl, commit 555697737ef0f0280ba7521fe788ce8b4ebab492 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Thu Jan 30 15:40:00 2020 +0300 don't even start to fill in a structure, if we can't allocate the prerequisites FIXME: There are other similar placase in this code; have a look at them and possibly re-organize. (E.g., pkgCacheGenerator::ListParser::NewDepends(), apart from pkgCacheGenerator::ListParser::NewProvides() already changed here.) diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc index 4c6055cbb..fe0a4e86e 100644 --- a/apt/apt-pkg/pkgcachegen.cc +++ b/apt/apt-pkg/pkgcachegen.cc @@ -559,11 +559,27 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, if (Ver.ParentPkg().Name() == PackageName) return true; #endif - + + // used only if !Version.empty() + std::experimental::optional<unsigned long> idxVersion = std::experimental::nullopt; + // Try to allocate the prerequisite string + if (Version.empty() == false) { + idxVersion = WriteString(Version); + if (!idxVersion) + { + /* Don't even start to fill in the structure below, + if we can't get the prerequisite. */ + return false; + } + } // Get a structure const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); if (!Provides) return false; + /* Note: + this accounting is done only if all the prerequistes have been allocated + and hence the structure will actually be used (filled in). + */ Cache.HeaderP->ProvidesCount++; // Fill it in @@ -572,16 +588,10 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); - if (Version.empty() == false) + if (idxVersion) { - const auto idxVersion = WriteString(Version); - // FIXME: If this allocation fails, did it make sense to fill in Prv above? - if (!idxVersion) - { - // FIXME: Does it really make sense to fill it in on failure? - Prv->ProvideVersion = 0; - return false; - } + /* FIXME: If Version.empty(), this field has never been touched. + Is this correct? */ Prv->ProvideVersion = *idxVersion; } commit b06f43d3c951ba7b2da8108516b551f1207beed6 Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Wed Jan 29 21:40:53 2020 +0300 DynamicMMap::RawAllocate(): error on "Can't allocate an item of size zero" Picked this single change from: commit 6d5e6a689d07de8feef2cbecb24bc42d5994861b Author: Aleksei Nikiforov <darktemplar@altlinux.org> Date: Tue Jun 11 14:53:47 2019 +0300 apt-pkg/pkgcachegen.{cc,h} changes make the used MMap moveable (and therefore dynamic resizeable) by applying (some) mad pointer magic Ported from Apt from Debian and adapted to the new return type. diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc index 77aad3656..ad49326df 100644 --- a/apt/apt-pkg/contrib/mmap.cc +++ b/apt/apt-pkg/contrib/mmap.cc @@ -226,6 +226,12 @@ std::experimental::optional<unsigned long> DynamicMMap::RawAllocate(unsigned lon size in the file. */ std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize) { + if (ItemSize == 0) + { + _error->Error("Can't allocate an item of size zero"); + return std::experimental::nullopt; + } + // Look for a matching pool entry Pool *I; Pool *Empty = 0; commit b92df3199a5eda44f5108e6721c5cb76d946d0fc Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Thu Jan 30 01:28:56 2020 +0300 rpmindexfile.cc rpmPkgListIndex::Merge(): drop a bogus call to FileFd::Seek() This operation couldn't have any noticeable effect, because the corresponding FileFd object is about to be destroyed: it's the end of its scope. (Note that it was declared and constructed 4 lines above. This explanation was given by darktemplar@ and quoted in https://lists.altlinux.org/pipermail/devel/2020-January/209736.html .) This single change has been picked from the following changeset (which otherwise has a different common purpose): commit 667677a7d268aaf0f84ce3bc0567c5350db20ec6 Author: Aleksei Nikiforov <darktemplar@altlinux.org> Date: Thu Jun 13 12:35:49 2019 +0300 Use special type to return allocation failure since 0 is a valid offset value This change will slightly alleviate the rewriting of code at this place for rigorous error-handling (which is a change also present in the cited-above commit 667677a7d268aaf0f84ce3bc0567c5350db20ec6, but not related to its purpose). diff --git a/apt/apt-pkg/rpm/rpmindexfile.cc b/apt/apt-pkg/rpm/rpmindexfile.cc index 271cd8f83..a66d4482c 100644 --- a/apt/apt-pkg/rpm/rpmindexfile.cc +++ b/apt/apt-pkg/rpm/rpmindexfile.cc @@ -407,7 +407,6 @@ bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const if (_error->PendingError() == true) return false; Parser.LoadReleaseInfo(File,Rel); - Rel.Seek(0); } return true; commit 7db04197e0029146ace692a4fa9ee7088dd76b8a (@ALT/optional, optional) Author: Ivan Zakharyaschev <imz@altlinux.org> Date: Thu Jan 30 04:44:06 2020 +0300 rpmindexfile.cc rpmPkgListIndex::Merge(): rigorously handle errors from Parser This single change has been picked from the following changeset (which otherwise has a different common purpose): commit 667677a7d268aaf0f84ce3bc0567c5350db20ec6 Author: Aleksei Nikiforov <darktemplar@altlinux.org> Date: Thu Jun 13 12:35:49 2019 +0300 Use special type to return allocation failure since 0 is a valid offset value Unfortunately, that commit doesn't explain why the new behavior is better than the old one (ignoring the error from Parser). diff --git a/apt/apt-pkg/rpm/rpmindexfile.cc b/apt/apt-pkg/rpm/rpmindexfile.cc index a66d4482c..5ba42155c 100644 --- a/apt/apt-pkg/rpm/rpmindexfile.cc +++ b/apt/apt-pkg/rpm/rpmindexfile.cc @@ -406,7 +406,8 @@ bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const FileFd Rel(RelFile,FileFd::ReadOnly); if (_error->PendingError() == true) return false; - Parser.LoadReleaseInfo(File,Rel); + if (!Parser.LoadReleaseInfo(File,Rel)) + return false; } return true; -- Best regards, Ivan
next prev parent reply other threads:[~2020-02-11 13:47 UTC|newest] Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-01-29 16:24 ` Ivan Zakharyaschev 2020-01-29 16:32 ` Ivan Zakharyaschev 2020-01-30 9:30 ` Aleksei Nikiforov 2020-01-30 8:56 ` Aleksei Nikiforov 2020-02-11 13:47 ` Ivan Zakharyaschev [this message] 2020-02-11 13:51 ` [devel] std::optional; was: " Ivan Zakharyaschev 2020-02-11 20:06 ` [devel] std::optional Dmitry V. Levin 2020-02-11 14:00 ` [devel] [SCM] packages/apt: heads/rework-dynamic-mmap Dmitry V. Levin 2020-02-11 14:24 ` Ivan Zakharyaschev 2020-02-11 17:05 ` Ivan Zakharyaschev 2020-02-11 18:14 ` Dmitry V. Levin 2020-02-12 2:14 ` Ivan Zakharyaschev 2020-02-12 8:47 ` Dmitry V. Levin
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=alpine.LFD.2.20.2002111638550.6363@imap.altlinux.org \ --to=imz@altlinux.org \ --cc=devel@lists.altlinux.org \ --cc=rider@altlinux.org \ --cc=vseleznv@altlinux.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
ALT Linux Team development discussions This inbox may be cloned and mirrored by anyone: git clone --mirror http://lore.altlinux.org/devel/0 devel/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 devel devel/ http://lore.altlinux.org/devel \ devel@altlinux.org devel@altlinux.ru devel@lists.altlinux.org devel@lists.altlinux.ru devel@linux.iplabs.ru mandrake-russian@linuxteam.iplabs.ru sisyphus@linuxteam.iplabs.ru public-inbox-index devel Example config snippet for mirrors. Newsgroup available over NNTP: nntp://lore.altlinux.org/org.altlinux.lists.devel AGPL code for this site: git clone https://public-inbox.org/public-inbox.git