ALT Linux Team development discussions
 help / color / mirror / Atom feed
* [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
@ 2020-02-13  2:08 Ivan Zakharyaschev
  2020-02-13  2:43 ` Ivan Zakharyaschev
  2020-02-13 12:59 ` Aleksei Nikiforov
  0 siblings, 2 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-13  2:08 UTC (permalink / raw)
  To: darktemplar, devel

[-- Attachment #1: Type: text/plain, Size: 8198 bytes --]

В ветке sisyphus_one_more_time в
git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите

commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547
Author: Aleksei Nikiforov <darktemplar@altlinux.org>
Date:   Tue Jun 11 14:53:47 2019 +0300

    dynamic memory management: 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
    
    Closes: https://bugzilla.altlinux.org/37373
    
    Change-Id: I4583e13077e7504ec8f59df4bcf3bc825eaf6202

есть такой hunk касательно DynamicMMap::RawAllocate():

diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
index d7a5c3a68..36dc11524 100644
--- a/apt/apt-pkg/contrib/mmap.cc
+++ b/apt/apt-pkg/contrib/mmap.cc
@@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
    size in the file. */
 unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
 {   
+   if (ItemSize == 0)
+   {
+      _error->Error("Can't allocate an item of size zero");
+      return 0;
+   }
+
    // Look for a matching pool entry
    Pool *I;
    Pool *Empty = 0;

(Весь контекст изменений в этой функции в конце письма.)

Во-первых, почему бы это изменение не оформить отдельным коммитом, ведь
оно касается проверки правильности аргументов функции и не связано
тесно с тем, есть ли у нас динамическое изменение размера DynamicMMap
с помощью realloc/mremap? (Кстати, summary в коммите можно было бы
сделать более информативным, чем просто "changes".)

Во-вторых, я подумал, что это такой класс ошибок, который не возникает
в run-time из-за плохих данных или отказа ОС (например, выделить
память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
для программиста и поэтому требующее специальной обработки в run-time.

Если програмист написал всё так, как он хотел, то он не передаст
неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
коде APT это не ожидается: там обычно этот аргумент заполняется
константой sizeof(...).)

Я бы предложил такие требования (имеющие характер спецификации того,
что программист задумал реализовать) оформлять просто с помощью
assert.

Так будет легче понимать код: сразу ясно, что выполнение этого условия
(важного для корректности кода в теле функции) просто гарантируется
тем, как весь наш код написан и вообще-то может быть обосновано ещё до
run-time (просто глядя на исходный код, на том же этапе работы, что и
запускаем компилятор).

Для справки: единственный вызов Allocate() в коде, который находится с
помощью

git grep -nH -Ee '(^|[^[:alpha:]])Allocate\('

это:

std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
   void *oldMap = Map.Data();
   const auto index = Map.Allocate(size);
   if (index)
      ReMap(oldMap, Map.Data());
   return index;
}

поищем, как используется AllocateInMap():

git --no-pager grep -nH -Ee '(^|[^[:alpha:]])AllocateInMap\('
apt/apt-pkg/pkgcachegen.cc:167:std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
apt/apt-pkg/pkgcachegen.cc:449:   const auto Package = AllocateInMap(sizeof(pkgCache::Package));
apt/apt-pkg/pkgcachegen.cc:502:   const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
apt/apt-pkg/pkgcachegen.cc:533:   const auto Version = AllocateInMap(sizeof(pkgCache::Version));
apt/apt-pkg/pkgcachegen.cc:561:   const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency));
apt/apt-pkg/pkgcachegen.cc:639:   const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
apt/apt-pkg/pkgcachegen.cc:686:   const auto idxFile = AllocateInMap(sizeof(*CurrentFile));
apt/apt-pkg/pkgcachegen.cc:744:   const auto Item = AllocateInMap(sizeof(pkgCache::StringItem));
apt/apt-pkg/pkgcachegen.h:45:   std::experimental::optional<map_ptrloc> AllocateInMap(unsigned long size);

-- как я и подозревал, константа времени компиляции sizeof(...).

Я за assert в обсуждаемом месте.

Примеры использования assert в коде APT:

git --no-pager grep -nH -Ee '(^|[^_[:alpha:]])assert\('
apt/apt-pkg/acquire-item.cc:309:	 assert(Repository == NULL || Repository->IsAuthenticated() == false);
apt/apt-pkg/acquire-item.cc:390:   assert(Master == false || Repository != NULL);
apt/apt-pkg/luaiface.cc:125:   assert(lua_istable(L, -1));
apt/apt-pkg/luaiface.cc:198:   assert(lua_istable(L, -1));
apt/apt-pkg/luaiface.cc:220:	 assert(lua_gettop(L) == 0);
apt/apt-pkg/pkgcache.cc:421:	 assert(Size < sizeof(Res)/sizeof(*Res));
apt/apt-pkg/pkgcache.cc:450:	 assert(Size < sizeof(Res)/sizeof(*Res));
apt/apt-pkg/rpm/rpmhandler.cc:106:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmhandler.cc:112:   assert(rc != 0);
apt/apt-pkg/rpm/rpmhandler.cc:124:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmhandler.cc:141:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmhandler.cc:149:      assert(i != NULL);
apt/apt-pkg/rpm/rpmhandler.cc:162:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmhandler.cc:207:   assert(Offset == 0);
apt/apt-pkg/rpm/rpmrecords.cc:92:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:114:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:128:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:146:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:211:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:329:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmrecords.cc:369:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/apt-pkg/rpm/rpmrecords.cc:406:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/apt-pkg/rpm/rpmrecords.cc:423:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/apt-pkg/rpm/rpmrecords.cc:440:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/apt-pkg/rpm/rpmsrcrecords.cc:71:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmsrcrecords.cc:89:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmsrcrecords.cc:136:   assert(HeaderP != NULL);
apt/apt-pkg/rpm/rpmsrcrecords.cc:378:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/apt-pkg/rpm/rpmsrcrecords.cc:415:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
apt/buildlib/ltmain.sh:4808:  assert(path != NULL);
apt/buildlib/ltmain.sh:4833:  assert(str != NULL);
apt/buildlib/ltmain.sh:4834:  assert(pat != NULL);
apt/lua/lapi.c:38:#define api_check(L, o)		/*{ assert(o); }*/
apt/lua/ltests.c:358:  assert(lua_gettop(L) == level+1);  /* +1 for result */
apt/lua/ltests.c:365:  assert(lua_gettop(L) == level+1);
apt/lua/ltests.c:372:  assert(lua_gettop(L) == level);
apt/tools/cached_md5.cc:45:      assert(p1);
apt/tools/cached_md5.cc:50:      assert(p2);
apt/tools/genpkglist.cc:206:   assert(l1.bnc == l1.dic);
apt/tools/genpkglist.cc:237:   assert(l2.bnc == l2.dic);


* * *

Весь контекст изменений в DynamicMMap::RawAllocate():

diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
index d7a5c3a68..36dc11524 100644
--- a/apt/apt-pkg/contrib/mmap.cc
+++ b/apt/apt-pkg/contrib/mmap.cc
@@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
    size in the file. */
 unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
 {   
+   if (ItemSize == 0)
+   {
+      _error->Error("Can't allocate an item of size zero");
+      return 0;
+   }
+
    // Look for a matching pool entry
    Pool *I;
    Pool *Empty = 0;
@@ -252,15 +277,26 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
       I->Count = 0;
    }
    
+   unsigned long Result = 0;
    // Out of space, allocate some more
    if (I->Count == 0)
    {
-      I->Count = 20*1024/ItemSize;
-      I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
-   }   
+      const unsigned long size = 20*1024;
+      I->Count = size/ItemSize;
+      Pool* oldPools = Pools;
+      Result = RawAllocate(I->Count*ItemSize,ItemSize);
+      if (Result == 0)
+         return 0;
+
+      if (Pools != oldPools)
+         I = RebasePointer(I, oldPools, Pools);
+
+      I->Start = Result;
+   }
+   else
+      Result = I->Start;
 
    I->Count--;
-   unsigned long Result = I->Start;
    I->Start += ItemSize;  
    return Result/ItemSize;
 }

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13  2:08 [devel] re APT patch with impossible error on "Can't allocate an item of size zero" Ivan Zakharyaschev
@ 2020-02-13  2:43 ` Ivan Zakharyaschev
  2020-02-13 12:59 ` Aleksei Nikiforov
  1 sibling, 0 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-13  2:43 UTC (permalink / raw)
  To: ALT Linux Team development discussions; +Cc: darktemplar

[-- Attachment #1: Type: text/plain, Size: 4248 bytes --]


On Thu, 13 Feb 2020, Ivan Zakharyaschev wrote:

> В ветке sisyphus_one_more_time в
> git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите
> 
> commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547

> есть такой hunk касательно DynamicMMap::RawAllocate():

> Во-вторых, я подумал, что это такой класс ошибок, который не возникает
> в run-time из-за плохих данных или отказа ОС (например, выделить
> память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
> для программиста и поэтому требующее специальной обработки в run-time.
> 
> Если програмист написал всё так, как он хотел, то он не передаст
> неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
> коде APT это не ожидается: там обычно этот аргумент заполняется
> константой sizeof(...).)
> 
> Я бы предложил такие требования (имеющие характер спецификации того,
> что программист задумал реализовать) оформлять просто с помощью
> assert.

Отразил это в коммите у себя в ветке, которая должна будет 
конвергироваться с sisyphus_one_more_time

commit ab3d7b79f9a582d4b01efad5e9fdf1a0455f735f
Author: Ivan Zakharyaschev <imz@altlinux.org>
Date:   Wed Jan 29 21:40:53 2020 +0300

    DynamicMMap::RawAllocate(): assert that a zero-size item is never allocated
    
    Actually, we are always called with sizeof(...)
    compile-time non-zero constant as the argument:
    
    The only invocation of Allocate() that can be found with:
    
    git grep -nH -Ee '(^|[^[:alpha:]])Allocate\('
    
    is the following function:
    
    std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
       void *oldMap = Map.Data();
       const auto index = Map.Allocate(size);
       if (index)
          ReMap(oldMap, Map.Data());
       return index;
    }
    
    Now, look how AllocateInMap() is used:
    
    git --no-pager grep -nH -Ee '(^|[^[:alpha:]])AllocateInMap\('
    apt/apt-pkg/pkgcachegen.cc:167:std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
    apt/apt-pkg/pkgcachegen.cc:449:   const auto Package = AllocateInMap(sizeof(pkgCache::Package));
    apt/apt-pkg/pkgcachegen.cc:502:   const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
    apt/apt-pkg/pkgcachegen.cc:533:   const auto Version = AllocateInMap(sizeof(pkgCache::Version));
    apt/apt-pkg/pkgcachegen.cc:561:   const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency));
    apt/apt-pkg/pkgcachegen.cc:639:   const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
    apt/apt-pkg/pkgcachegen.cc:686:   const auto idxFile = AllocateInMap(sizeof(*CurrentFile));
    apt/apt-pkg/pkgcachegen.cc:744:   const auto Item = AllocateInMap(sizeof(pkgCache::StringItem));
    apt/apt-pkg/pkgcachegen.h:45:   std::experimental::optional<map_ptrloc> AllocateInMap(unsigned long size);
    
    The argument is always a sizeof(...) constant expression.
    
    Picked the idea of 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
    
    but rewritten with an assert statement.

diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
index 77aad3656..e0373365a 100644
--- a/apt/apt-pkg/contrib/mmap.cc
+++ b/apt/apt-pkg/contrib/mmap.cc
@@ -37,6 +37,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <cstring>
+#include <cassert>
    									/*}}}*/
 
 // MMap::MMap - Constructor						/*{{{*/
@@ -226,6 +227,10 @@ std::experimental::optional<unsigned long> DynamicMMap::RawAllocate(unsigned lon
    size in the file. */
 std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize)
 {
+   assert(ItemSize != 0); /* Actually, we are always called with sizeof(...)
+                             compile-time non-zero constant as the argument.
+                          */
+
    // Look for a matching pool entry
    Pool *I;
    Pool *Empty = 0;

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13  2:08 [devel] re APT patch with impossible error on "Can't allocate an item of size zero" Ivan Zakharyaschev
  2020-02-13  2:43 ` Ivan Zakharyaschev
@ 2020-02-13 12:59 ` Aleksei Nikiforov
  2020-02-13 14:10   ` Ivan Zakharyaschev
  2020-02-13 14:51   ` Ivan Zakharyaschev
  1 sibling, 2 replies; 11+ messages in thread
From: Aleksei Nikiforov @ 2020-02-13 12:59 UTC (permalink / raw)
  To: Ivan Zakharyaschev; +Cc: ALT Linux Team development discussions

13.02.2020 05:08, Ivan Zakharyaschev пишет:
> В ветке sisyphus_one_more_time в
> git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите
> 
> commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547
> Author: Aleksei Nikiforov <darktemplar@altlinux.org>
> Date:   Tue Jun 11 14:53:47 2019 +0300
> 
>      dynamic memory management: 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
>      
>      Closes: https://bugzilla.altlinux.org/37373
>      
>      Change-Id: I4583e13077e7504ec8f59df4bcf3bc825eaf6202
> 
> есть такой hunk касательно DynamicMMap::RawAllocate():
> 
> diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> index d7a5c3a68..36dc11524 100644
> --- a/apt/apt-pkg/contrib/mmap.cc
> +++ b/apt/apt-pkg/contrib/mmap.cc
> @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
>      size in the file. */
>   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
>   {
> +   if (ItemSize == 0)
> +   {
> +      _error->Error("Can't allocate an item of size zero");
> +      return 0;
> +   }
> +
>      // Look for a matching pool entry
>      Pool *I;
>      Pool *Empty = 0;
> 
> (Весь контекст изменений в этой функции в конце письма.)
> 
> Во-первых, почему бы это изменение не оформить отдельным коммитом, ведь

Если в этом есть необходимость, пожалуй, можно вынести это изменение в 
отдельный коммит. А она есть?

> оно касается проверки правильности аргументов функции и не связано
> тесно с тем, есть ли у нас динамическое изменение размера DynamicMMap

Никак не связано. Не тот уровень абстракции.

> с помощью realloc/mremap? (Кстати, summary в коммите можно было бы
> сделать более информативным, чем просто "changes".)
> 

Оригинальный commit message был взять из коммита, портируемого из Debian 
и не менялся, и без веских оснований не планирует меняться.

> Во-вторых, я подумал, что это такой класс ошибок, который не возникает
> в run-time из-за плохих данных или отказа ОС (например, выделить
> память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
> для программиста и поэтому требующее специальной обработки в run-time.
> 
> Если програмист написал всё так, как он хотел, то он не передаст
> неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
> коде APT это не ожидается: там обычно этот аргумент заполняется
> константой sizeof(...).)
> 

Ты упускаешь большой момент. mmap.h - публичный заголовок библиотеки 
libapt. Помимо самого apt, им пользуется ещё и немало клиентов. Даже 
если в самом apt не найдётся способа неправильно вызвать данную функцию, 
это ничего не значит. Не проверять входные данные - плохая идея.

> Я бы предложил такие требования (имеющие характер спецификации того,
> что программист задумал реализовать) оформлять просто с помощью
> assert.
> 

assert в не-debug сборке отсутствует. Потому чуть более чем полностью 
бесполезен не во время разработки приложения. Это не средство проверки 
входных данных. Поэтому я против.

> Так будет легче понимать код: сразу ясно, что выполнение этого условия
> (важного для корректности кода в теле функции) просто гарантируется
> тем, как весь наш код написан и вообще-то может быть обосновано ещё до
> run-time (просто глядя на исходный код, на том же этапе работы, что и
> запускаем компилятор).
> 
> Для справки: единственный вызов Allocate() в коде, который находится с
> помощью
> 
> git grep -nH -Ee '(^|[^[:alpha:]])Allocate\('
> 
> это:
> 
> std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
>     void *oldMap = Map.Data();
>     const auto index = Map.Allocate(size);
>     if (index)
>        ReMap(oldMap, Map.Data());
>     return index;
> }
> 
> поищем, как используется AllocateInMap():
> 
> git --no-pager grep -nH -Ee '(^|[^[:alpha:]])AllocateInMap\('
> apt/apt-pkg/pkgcachegen.cc:167:std::experimental::optional<map_ptrloc> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
> apt/apt-pkg/pkgcachegen.cc:449:   const auto Package = AllocateInMap(sizeof(pkgCache::Package));
> apt/apt-pkg/pkgcachegen.cc:502:   const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
> apt/apt-pkg/pkgcachegen.cc:533:   const auto Version = AllocateInMap(sizeof(pkgCache::Version));
> apt/apt-pkg/pkgcachegen.cc:561:   const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency));
> apt/apt-pkg/pkgcachegen.cc:639:   const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
> apt/apt-pkg/pkgcachegen.cc:686:   const auto idxFile = AllocateInMap(sizeof(*CurrentFile));
> apt/apt-pkg/pkgcachegen.cc:744:   const auto Item = AllocateInMap(sizeof(pkgCache::StringItem));
> apt/apt-pkg/pkgcachegen.h:45:   std::experimental::optional<map_ptrloc> AllocateInMap(unsigned long size);
> 
> -- как я и подозревал, константа времени компиляции sizeof(...).
> 
> Я за assert в обсуждаемом месте.
> 
> Примеры использования assert в коде APT:
> 
> git --no-pager grep -nH -Ee '(^|[^_[:alpha:]])assert\('
> apt/apt-pkg/acquire-item.cc:309:	 assert(Repository == NULL || Repository->IsAuthenticated() == false);
> apt/apt-pkg/acquire-item.cc:390:   assert(Master == false || Repository != NULL);
> apt/apt-pkg/luaiface.cc:125:   assert(lua_istable(L, -1));
> apt/apt-pkg/luaiface.cc:198:   assert(lua_istable(L, -1));
> apt/apt-pkg/luaiface.cc:220:	 assert(lua_gettop(L) == 0);
> apt/apt-pkg/pkgcache.cc:421:	 assert(Size < sizeof(Res)/sizeof(*Res));
> apt/apt-pkg/pkgcache.cc:450:	 assert(Size < sizeof(Res)/sizeof(*Res));
> apt/apt-pkg/rpm/rpmhandler.cc:106:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmhandler.cc:112:   assert(rc != 0);
> apt/apt-pkg/rpm/rpmhandler.cc:124:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmhandler.cc:141:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmhandler.cc:149:      assert(i != NULL);
> apt/apt-pkg/rpm/rpmhandler.cc:162:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmhandler.cc:207:   assert(Offset == 0);
> apt/apt-pkg/rpm/rpmrecords.cc:92:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:114:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:128:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:146:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:211:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:329:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmrecords.cc:369:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/apt-pkg/rpm/rpmrecords.cc:406:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/apt-pkg/rpm/rpmrecords.cc:423:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/apt-pkg/rpm/rpmrecords.cc:440:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/apt-pkg/rpm/rpmsrcrecords.cc:71:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmsrcrecords.cc:89:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmsrcrecords.cc:136:   assert(HeaderP != NULL);
> apt/apt-pkg/rpm/rpmsrcrecords.cc:378:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/apt-pkg/rpm/rpmsrcrecords.cc:415:   assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
> apt/buildlib/ltmain.sh:4808:  assert(path != NULL);
> apt/buildlib/ltmain.sh:4833:  assert(str != NULL);
> apt/buildlib/ltmain.sh:4834:  assert(pat != NULL);
> apt/lua/lapi.c:38:#define api_check(L, o)		/*{ assert(o); }*/
> apt/lua/ltests.c:358:  assert(lua_gettop(L) == level+1);  /* +1 for result */
> apt/lua/ltests.c:365:  assert(lua_gettop(L) == level+1);
> apt/lua/ltests.c:372:  assert(lua_gettop(L) == level);
> apt/tools/cached_md5.cc:45:      assert(p1);
> apt/tools/cached_md5.cc:50:      assert(p2);
> apt/tools/genpkglist.cc:206:   assert(l1.bnc == l1.dic);
> apt/tools/genpkglist.cc:237:   assert(l2.bnc == l2.dic);
> 
> 
> * * *
> 
> Весь контекст изменений в DynamicMMap::RawAllocate():
> 
> diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> index d7a5c3a68..36dc11524 100644
> --- a/apt/apt-pkg/contrib/mmap.cc
> +++ b/apt/apt-pkg/contrib/mmap.cc
> @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
>      size in the file. */
>   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
>   {
> +   if (ItemSize == 0)
> +   {
> +      _error->Error("Can't allocate an item of size zero");
> +      return 0;
> +   }
> +
>      // Look for a matching pool entry
>      Pool *I;
>      Pool *Empty = 0;
> @@ -252,15 +277,26 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
>         I->Count = 0;
>      }
>      
> +   unsigned long Result = 0;
>      // Out of space, allocate some more
>      if (I->Count == 0)
>      {
> -      I->Count = 20*1024/ItemSize;
> -      I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
> -   }
> +      const unsigned long size = 20*1024;
> +      I->Count = size/ItemSize;
> +      Pool* oldPools = Pools;
> +      Result = RawAllocate(I->Count*ItemSize,ItemSize);
> +      if (Result == 0)
> +         return 0;
> +
> +      if (Pools != oldPools)
> +         I = RebasePointer(I, oldPools, Pools);
> +
> +      I->Start = Result;
> +   }
> +   else
> +      Result = I->Start;
>   
>      I->Count--;
> -   unsigned long Result = I->Start;
>      I->Start += ItemSize;
>      return Result/ItemSize;
>   }
> 
> 
> _______________________________________________
> Devel mailing list
> Devel@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/devel
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13 12:59 ` Aleksei Nikiforov
@ 2020-02-13 14:10   ` Ivan Zakharyaschev
  2020-02-13 17:05     ` Ivan Zakharyaschev
  2020-02-17  8:41     ` Ivan Zakharyaschev
  2020-02-13 14:51   ` Ivan Zakharyaschev
  1 sibling, 2 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-13 14:10 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 9840 bytes --]


On Thu, 13 Feb 2020, Aleksei Nikiforov wrote:

> 13.02.2020 05:08, Ivan Zakharyaschev пишет:
> > В ветке sisyphus_one_more_time в
> > git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите
> > 
> > commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547
> > Author: Aleksei Nikiforov <darktemplar@altlinux.org>
> > Date:   Tue Jun 11 14:53:47 2019 +0300
> > 
> >      dynamic memory management: 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
> >      
> >      Closes: https://bugzilla.altlinux.org/37373
> >      
> >      Change-Id: I4583e13077e7504ec8f59df4bcf3bc825eaf6202
> > 
> > есть такой hunk касательно DynamicMMap::RawAllocate():
> > 
> > diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> > index d7a5c3a68..36dc11524 100644
> > --- a/apt/apt-pkg/contrib/mmap.cc
> > +++ b/apt/apt-pkg/contrib/mmap.cc
> > @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long
> > Size,unsigned long Aln)
> >      size in the file. */
> >   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
> >   {
> > +   if (ItemSize == 0)
> > +   {
> > +      _error->Error("Can't allocate an item of size zero");
> > +      return 0;
> > +   }
> > +
> >      // Look for a matching pool entry
> >      Pool *I;
> >      Pool *Empty = 0;

> Оригинальный commit message был взять из коммита, портируемого из Debian и не
> менялся, и без веских оснований не планирует меняться.

Гмм.

> > Во-вторых, я подумал, что это такой класс ошибок, который не возникает
> > в run-time из-за плохих данных или отказа ОС (например, выделить
> > память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
> > для программиста и поэтому требующее специальной обработки в run-time.
> > 
> > Если програмист написал всё так, как он хотел, то он не передаст
> > неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
> > коде APT это не ожидается: там обычно этот аргумент заполняется
> > константой sizeof(...).)
> > 
> 
> Ты упускаешь большой момент. mmap.h - публичный заголовок библиотеки libapt.
> Помимо самого apt, им пользуется ещё и немало клиентов. Даже если в самом apt
> не найдётся способа неправильно вызвать данную функцию, это ничего не значит.
> Не проверять входные данные - плохая идея.

Всё равно это ответственность программиста: правильно вызвать.

Я выше написал, в каких случаях я счиатю нужным проверять данные.

> > Я бы предложил такие требования (имеющие характер спецификации того,
> > что программист задумал реализовать) оформлять просто с помощью
> > assert.
> > 
> 
> assert в не-debug сборке отсутствует. Потому чуть более чем полностью
> бесполезен не во время разработки приложения.

Я так и задумывал.


> Это не средство проверки входных
> данных. Поэтому я против.
> 
> > Так будет легче понимать код: сразу ясно, что выполнение этого условия
> > (важного для корректности кода в теле функции) просто гарантируется
> > тем, как весь наш код написан и вообще-то может быть обосновано ещё до
> > run-time (просто глядя на исходный код, на том же этапе работы, что и
> > запускаем компилятор).
> > 
> > Для справки: единственный вызов Allocate() в коде, который находится с
> > помощью
> > 
> > git grep -nH -Ee '(^|[^[:alpha:]])Allocate\('
> > 
> > это:
> > 
> > std::experimental::optional<map_ptrloc>
> > pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
> >     void *oldMap = Map.Data();
> >     const auto index = Map.Allocate(size);
> >     if (index)
> >        ReMap(oldMap, Map.Data());
> >     return index;
> > }
> > 
> > поищем, как используется AllocateInMap():
> > 
> > git --no-pager grep -nH -Ee '(^|[^[:alpha:]])AllocateInMap\('
> > apt/apt-pkg/pkgcachegen.cc:167:std::experimental::optional<map_ptrloc>
> > pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
> > apt/apt-pkg/pkgcachegen.cc:449:   const auto Package =
> > AllocateInMap(sizeof(pkgCache::Package));
> > apt/apt-pkg/pkgcachegen.cc:502:   const auto VerFile =
> > AllocateInMap(sizeof(pkgCache::VerFile));
> > apt/apt-pkg/pkgcachegen.cc:533:   const auto Version =
> > AllocateInMap(sizeof(pkgCache::Version));
> > apt/apt-pkg/pkgcachegen.cc:561:   const auto Dependency =
> > Owner->AllocateInMap(sizeof(pkgCache::Dependency));
> > apt/apt-pkg/pkgcachegen.cc:639:   const auto Provides =
> > Owner->AllocateInMap(sizeof(pkgCache::Provides));
> > apt/apt-pkg/pkgcachegen.cc:686:   const auto idxFile =
> > AllocateInMap(sizeof(*CurrentFile));
> > apt/apt-pkg/pkgcachegen.cc:744:   const auto Item =
> > AllocateInMap(sizeof(pkgCache::StringItem));
> > apt/apt-pkg/pkgcachegen.h:45:   std::experimental::optional<map_ptrloc>
> > AllocateInMap(unsigned long size);
> > 
> > -- как я и подозревал, константа времени компиляции sizeof(...).
> > 
> > Я за assert в обсуждаемом месте.
> > 
> > Примеры использования assert в коде APT:
> > 
> > git --no-pager grep -nH -Ee '(^|[^_[:alpha:]])assert\('
> > apt/apt-pkg/acquire-item.cc:309:	 assert(Repository == NULL ||
> > Repository->IsAuthenticated() == false);
> > apt/apt-pkg/acquire-item.cc:390:   assert(Master == false || Repository !=
> > NULL);
> > apt/apt-pkg/luaiface.cc:125:   assert(lua_istable(L, -1));
> > apt/apt-pkg/luaiface.cc:198:   assert(lua_istable(L, -1));
> > apt/apt-pkg/luaiface.cc:220:	 assert(lua_gettop(L) == 0);
> > apt/apt-pkg/pkgcache.cc:421:	 assert(Size < sizeof(Res)/sizeof(*Res));
> > apt/apt-pkg/pkgcache.cc:450:	 assert(Size < sizeof(Res)/sizeof(*Res));
> > apt/apt-pkg/rpm/rpmhandler.cc:106:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmhandler.cc:112:   assert(rc != 0);
> > apt/apt-pkg/rpm/rpmhandler.cc:124:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmhandler.cc:141:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmhandler.cc:149:      assert(i != NULL);
> > apt/apt-pkg/rpm/rpmhandler.cc:162:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmhandler.cc:207:   assert(Offset == 0);
> > apt/apt-pkg/rpm/rpmrecords.cc:92:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:114:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:128:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:146:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:211:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:329:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmrecords.cc:369:   assert(type == RPM_STRING_ARRAY_TYPE ||
> > count == 0);
> > apt/apt-pkg/rpm/rpmrecords.cc:406:   assert(type == RPM_STRING_ARRAY_TYPE ||
> > count == 0);
> > apt/apt-pkg/rpm/rpmrecords.cc:423:   assert(type == RPM_STRING_ARRAY_TYPE ||
> > count == 0);
> > apt/apt-pkg/rpm/rpmrecords.cc:440:   assert(type == RPM_STRING_ARRAY_TYPE ||
> > count == 0);
> > apt/apt-pkg/rpm/rpmsrcrecords.cc:71:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmsrcrecords.cc:89:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmsrcrecords.cc:136:   assert(HeaderP != NULL);
> > apt/apt-pkg/rpm/rpmsrcrecords.cc:378:   assert(type == RPM_STRING_ARRAY_TYPE
> > || count == 0);
> > apt/apt-pkg/rpm/rpmsrcrecords.cc:415:   assert(type == RPM_STRING_ARRAY_TYPE
> > || count == 0);
> > apt/buildlib/ltmain.sh:4808:  assert(path != NULL);
> > apt/buildlib/ltmain.sh:4833:  assert(str != NULL);
> > apt/buildlib/ltmain.sh:4834:  assert(pat != NULL);
> > apt/lua/lapi.c:38:#define api_check(L, o)		/*{ assert(o); }*/
> > apt/lua/ltests.c:358:  assert(lua_gettop(L) == level+1);  /* +1 for result
> > */
> > apt/lua/ltests.c:365:  assert(lua_gettop(L) == level+1);
> > apt/lua/ltests.c:372:  assert(lua_gettop(L) == level);
> > apt/tools/cached_md5.cc:45:      assert(p1);
> > apt/tools/cached_md5.cc:50:      assert(p2);
> > apt/tools/genpkglist.cc:206:   assert(l1.bnc == l1.dic);
> > apt/tools/genpkglist.cc:237:   assert(l2.bnc == l2.dic);
> > 
> > 
> > * * *
> > 
> > Весь контекст изменений в DynamicMMap::RawAllocate():
> > 
> > diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> > index d7a5c3a68..36dc11524 100644
> > --- a/apt/apt-pkg/contrib/mmap.cc
> > +++ b/apt/apt-pkg/contrib/mmap.cc
> > @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long
> > Size,unsigned long Aln)
> >      size in the file. */
> >   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
> >   {
> > +   if (ItemSize == 0)
> > +   {
> > +      _error->Error("Can't allocate an item of size zero");
> > +      return 0;
> > +   }
> > +
> >      // Look for a matching pool entry
> >      Pool *I;
> >      Pool *Empty = 0;
> > @@ -252,15 +277,26 @@ unsigned long DynamicMMap::Allocate(unsigned long
> > ItemSize)
> >         I->Count = 0;
> >      }
> >      
> > +   unsigned long Result = 0;
> >      // Out of space, allocate some more
> >      if (I->Count == 0)
> >      {
> > -      I->Count = 20*1024/ItemSize;
> > -      I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
> > -   }
> > +      const unsigned long size = 20*1024;
> > +      I->Count = size/ItemSize;
> > +      Pool* oldPools = Pools;
> > +      Result = RawAllocate(I->Count*ItemSize,ItemSize);
> > +      if (Result == 0)
> > +         return 0;
> > +
> > +      if (Pools != oldPools)
> > +         I = RebasePointer(I, oldPools, Pools);
> > +
> > +      I->Start = Result;
> > +   }
> > +   else
> > +      Result = I->Start;
> >   
> >      I->Count--;
> > -   unsigned long Result = I->Start;
> >      I->Start += ItemSize;
> >      return Result/ItemSize;
> >   }
> > 
> > 
> > _______________________________________________
> > Devel mailing list
> > Devel@lists.altlinux.org
> > https://lists.altlinux.org/mailman/listinfo/devel
> > 
> _______________________________________________
> Devel mailing list
> Devel@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/devel
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13 12:59 ` Aleksei Nikiforov
  2020-02-13 14:10   ` Ivan Zakharyaschev
@ 2020-02-13 14:51   ` Ivan Zakharyaschev
  1 sibling, 0 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-13 14:51 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 1850 bytes --]


On Thu, 13 Feb 2020, Aleksei Nikiforov wrote:

> 13.02.2020 05:08, Ivan Zakharyaschev пишет:
> > В ветке sisyphus_one_more_time в
> > git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите
> > 
> > commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547
> > Author: Aleksei Nikiforov <darktemplar@altlinux.org>
> > Date:   Tue Jun 11 14:53:47 2019 +0300
> > 
> >      dynamic memory management: 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
> >      
> >      Closes: https://bugzilla.altlinux.org/37373
> >      
> >      Change-Id: I4583e13077e7504ec8f59df4bcf3bc825eaf6202
> > 
> > есть такой hunk касательно DynamicMMap::RawAllocate():
> > 
> > diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> > index d7a5c3a68..36dc11524 100644
> > --- a/apt/apt-pkg/contrib/mmap.cc
> > +++ b/apt/apt-pkg/contrib/mmap.cc
> > @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long
> > Size,unsigned long Aln)
> >      size in the file. */
> >   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
> >   {
> > +   if (ItemSize == 0)
> > +   {
> > +      _error->Error("Can't allocate an item of size zero");
> > +      return 0;
> > +   }
> > +
> >      // Look for a matching pool entry
> >      Pool *I;
> >      Pool *Empty = 0;
> > 
> > (Весь контекст изменений в этой функции в конце письма.)
> > 
> > Во-первых, почему бы это изменение не оформить отдельным коммитом, ведь
> 
> Если в этом есть необходимость, пожалуй, можно вынести это изменение в
> отдельный коммит. А она есть?

Не берусь оценить серьёзность необходимости, но так же нам (нынешним и 
будущим APT-программистам) легче будет изучать изменения.

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13 14:10   ` Ivan Zakharyaschev
@ 2020-02-13 17:05     ` Ivan Zakharyaschev
  2020-02-17  8:41     ` Ivan Zakharyaschev
  1 sibling, 0 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-13 17:05 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 1449 bytes --]


On Thu, 13 Feb 2020, Ivan Zakharyaschev wrote:

> 
> On Thu, 13 Feb 2020, Aleksei Nikiforov wrote:
> 
> > 13.02.2020 05:08, Ivan Zakharyaschev пишет:
> > > В ветке sisyphus_one_more_time в
> > > git://git.altlinux.org/people/darktemplar/packages/apt.git в коммите
> > > 
> > > commit f53c1af17e2997ff6d2e23139bc61f5d5c82a547
> > > Author: Aleksei Nikiforov <darktemplar@altlinux.org>
> > > Date:   Tue Jun 11 14:53:47 2019 +0300
> > > 
> > >      dynamic memory management: 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
> > >      
> > >      Closes: https://bugzilla.altlinux.org/37373
> > >      
> > >      Change-Id: I4583e13077e7504ec8f59df4bcf3bc825eaf6202
> 
> > Оригинальный commit message был взять из коммита, портируемого из Debian и не
> > менялся, и без веских оснований не планирует меняться.
> 
> Гмм.

А id оргинального коммита не указан? Было бы хоршшо сослаться.

Создаётся впечатление, что это авторская переработка их кода, и раз уж код 
переработан, то какой смысл держаться за их commit message?

С другой стороны: так кто же автор этого коммита? git пишет, что ты. Тогда 
тебе и решать в первую очередь, что писать в сообщении и как сделать так, 
чтобы оно несло полезную информацию для мейнтейнеров и знакомящихся с 
историей.

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-13 14:10   ` Ivan Zakharyaschev
  2020-02-13 17:05     ` Ivan Zakharyaschev
@ 2020-02-17  8:41     ` Ivan Zakharyaschev
  2020-02-17 14:05       ` Andrey Savchenko
  2020-02-17 21:35       ` Dmitry V. Levin
  1 sibling, 2 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-17  8:41 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 9894 bytes --]

Hello!

On Thu, 13 Feb 2020, Ivan Zakharyaschev wrote:

> > > есть такой hunk касательно DynamicMMap::RawAllocate():
> > > 
> > > diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> > > index d7a5c3a68..36dc11524 100644
> > > --- a/apt/apt-pkg/contrib/mmap.cc
> > > +++ b/apt/apt-pkg/contrib/mmap.cc
> > > @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long
> > > Size,unsigned long Aln)
> > >      size in the file. */
> > >   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
> > >   {
> > > +   if (ItemSize == 0)
> > > +   {
> > > +      _error->Error("Can't allocate an item of size zero");
> > > +      return 0;
> > > +   }
> > > +
> > >      // Look for a matching pool entry
> > >      Pool *I;
> > >      Pool *Empty = 0;

> > > Во-вторых, я подумал, что это такой класс ошибок, который не возникает
> > > в run-time из-за плохих данных или отказа ОС (например, выделить
> > > память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
> > > для программиста и поэтому требующее специальной обработки в run-time.
> > > 
> > > Если програмист написал всё так, как он хотел, то он не передаст
> > > неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
> > > коде APT это не ожидается: там обычно этот аргумент заполняется
> > > константой sizeof(...).)
> > > 
> > 
> > Ты упускаешь большой момент. mmap.h - публичный заголовок библиотеки libapt.
> > Помимо самого apt, им пользуется ещё и немало клиентов. Даже если в самом apt
> > не найдётся способа неправильно вызвать данную функцию, это ничего не значит.
> > Не проверять входные данные - плохая идея.
> 
> Всё равно это ответственность программиста: правильно вызвать.
> 
> Я выше написал, в каких случаях я счиатю нужным проверять данные.
> 
> > > Я бы предложил такие требования (имеющие характер спецификации того,
> > > что программист задумал реализовать) оформлять просто с помощью
> > > assert.
> > > 
> > 
> > assert в не-debug сборке отсутствует. Потому чуть более чем полностью
> > бесполезен не во время разработки приложения.
> 
> Я так и задумывал.
> 
> 
> > Это не средство проверки входных
> > данных. Поэтому я против.
> > 
> > > Так будет легче понимать код: сразу ясно, что выполнение этого условия
> > > (важного для корректности кода в теле функции) просто гарантируется
> > > тем, как весь наш код написан и вообще-то может быть обосновано ещё до
> > > run-time (просто глядя на исходный код, на том же этапе работы, что и
> > > запускаем компилятор).

Появилась идея, что есть способ здесь не просто ответственность возложить 
на программиста на словах (вызывать Allocate() с ненулевым аргументом), но 
и формально предложить такой способ программирования, где не будет 
возможности делать не так, как задумано.

Да и попроще вызовы получаются.

Ветка alloc-templates в 
http://git.altlinux.org/people/imz/packages/apt.git

(Развивая это, можно RawAllocate() превратить в какой-нибудь
template<typename T> RawAllocateArray<T>(unsigned long ItemCount),
там, правда, Pools нетривиально надо будет переделать.

Пришлось, правда, перенести определение из .cc в .h и патчи дальнейшие 
неудобно прикладывать; но можно их ifdef-ами обложить в .cc и заинклудить 
в .h.)

>From 89499e5810575336e6a3b02d71d6c323321a0eca Mon Sep 17 00:00:00 2001
From: Ivan Zakharyaschev <imz@altlinux.org>
Date: Fri, 14 Feb 2020 04:04:42 +0300
Subject: [PATCH] don't pass compile-time constants as an argument to
 DynamicMMap::Allocate()

The argument was used for the size of the item we want to allocate.

Instead of an argument, use a parameter for the template DynamicMMap::Allocate()
which denotes the type of the item.

Now, the truth of our assertion that the size is not zero is evident
(and checked by the compiler).

Note that this change may also potentially lead to more optimized code
due to compile-time specialization for each particular size.
---
 apt/apt-pkg/contrib/mmap.h | 12 ++++++------
 apt/apt-pkg/pkgcachegen.cc | 19 ++++++++++---------
 apt/apt-pkg/pkgcachegen.h  |  3 ++-
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/apt/apt-pkg/contrib/mmap.h b/apt/apt-pkg/contrib/mmap.h
index 5b14ac9d9..7ec0fb8b1 100644
--- a/apt/apt-pkg/contrib/mmap.h
+++ b/apt/apt-pkg/contrib/mmap.h
@@ -94,7 +94,8 @@ class DynamicMMap : public MMap
 
    // Allocation
    std::experimental::optional<unsigned long> RawAllocate(unsigned long Size,unsigned long Aln = 0);
-   std::experimental::optional<unsigned long> Allocate(unsigned long ItemSize);
+   template<typename T>
+   std::experimental::optional<unsigned long> Allocate();
    std::experimental::optional<unsigned long> WriteString(const char *String,unsigned long Len = std::numeric_limits<unsigned long>::max());
    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;};
@@ -107,17 +108,16 @@ class DynamicMMap : public MMap
 /* Templates */
 
 #include <apt-pkg/error.h>
-#include <cassert>
 
 // DynamicMMap::Allocate - Pooled aligned allocation			/*{{{*/
 // ---------------------------------------------------------------------
 /* This allocates an Item of size ItemSize so that it is aligned to its
    size in the file. */
-std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize)
+template<typename T>
+std::experimental::optional<unsigned long> DynamicMMap::Allocate()
 {
-   assert(ItemSize != 0); /* Actually, we are always called with sizeof(...)
-                             compile-time non-zero constant as the argument.
-                          */
+   constexpr unsigned long ItemSize = sizeof(T);
+   static_assert(ItemSize != 0);
 
    // Look for a matching pool entry
    Pool *I;
diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc
index 4bbab07bf..2a75f31e6 100644
--- a/apt/apt-pkg/pkgcachegen.cc
+++ b/apt/apt-pkg/pkgcachegen.cc
@@ -112,8 +112,9 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::WriteStringInMap(c
    return Map.WriteString(String);
 }
 									/*}}}*/
-std::experimental::optional<unsigned long> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
-   return Map.Allocate(size);
+template<typename T>
+std::experimental::optional<unsigned long> pkgCacheGenerator::AllocateInMap() {/*{{{*/
+   return Map.Allocate<T>();
 }
 									/*}}}*/
 // CacheGenerator::MergeList - Merge the package list			/*{{{*/
@@ -376,7 +377,7 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg, const string &Nam
 #endif
        
    // Get a structure
-   const auto Package = AllocateInMap(sizeof(pkgCache::Package));
+   const auto Package = AllocateInMap<pkgCache::Package>();
    const auto idxName = WriteStringInMap(Name);
    if ((!Package) || (!idxName))
       return false;
@@ -429,7 +430,7 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
       return true;
    
    // Get a structure
-   const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
+   const auto VerFile = AllocateInMap<pkgCache::VerFile>();
    if (!VerFile)
       return false;
    
@@ -460,7 +461,7 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::NewVersion(pkgCach
 					    unsigned long Next)
 {
    // Get a structure
-   const auto Version = AllocateInMap(sizeof(pkgCache::Version));
+   const auto Version = AllocateInMap<pkgCache::Version>();
    const auto idxVerStr = WriteStringInMap(VerStr);
    if ((!Version) || (!idxVerStr))
       return std::experimental::nullopt;
@@ -487,7 +488,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
    pkgCache &Cache = Owner->Cache;
    
    // Get a structure
-   const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency));
+   const auto Dependency = Owner->AllocateInMap<pkgCache::Dependency>();
    if (!Dependency)
       return false;
    
@@ -574,7 +575,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
       }
    }
    // Get a structure
-   const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
+   const auto Provides = Owner->AllocateInMap<pkgCache::Provides>();
    if (!Provides)
       return false;
    /* Note:
@@ -618,7 +619,7 @@ bool pkgCacheGenerator::SelectFile(const string &File, const string &Site,
 				   unsigned long Flags)
 {
    // Get some space for the structure
-   const auto idxFile = AllocateInMap(sizeof(*CurrentFile));
+   const auto idxFile = AllocateInMap<decltype(*CurrentFile)>();
    const auto idxFileName = WriteStringInMap(File);
    const auto idxSite = WriteUniqString(Site);
    const auto idxIndexType = WriteUniqString(Index.GetType()->Label);
@@ -676,7 +677,7 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::WriteUniqString(co
    }
    
    // Get a structure
-   const auto Item = AllocateInMap(sizeof(pkgCache::StringItem));
+   const auto Item = AllocateInMap<pkgCache::StringItem>();
    const auto idxString = WriteStringInMap(S, Size);
    if ((!Item) || (!idxString))
       return std::experimental::nullopt;
diff --git a/apt/apt-pkg/pkgcachegen.h b/apt/apt-pkg/pkgcachegen.h
index b789177ef..73252802b 100644
--- a/apt/apt-pkg/pkgcachegen.h
+++ b/apt/apt-pkg/pkgcachegen.h
@@ -39,7 +39,8 @@ class pkgCacheGenerator
    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);
+   template<typename T>
+   std::experimental::optional<unsigned long> AllocateInMap();
 
    public:
    
-- 
2.21.0

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-17  8:41     ` Ivan Zakharyaschev
@ 2020-02-17 14:05       ` Andrey Savchenko
  2020-02-17 17:48         ` Ivan Zakharyaschev
  2020-02-17 21:35       ` Dmitry V. Levin
  1 sibling, 1 reply; 11+ messages in thread
From: Andrey Savchenko @ 2020-02-17 14:05 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 8834 bytes --]

On Mon, 17 Feb 2020 11:41:36 +0300 (MSK) Ivan Zakharyaschev wrote:
> Появилась идея, что есть способ здесь не просто ответственность возложить 
> на программиста на словах (вызывать Allocate() с ненулевым аргументом), но 
> и формально предложить такой способ программирования, где не будет 
> возможности делать не так, как задумано.
> 
> Да и попроще вызовы получаются.
> 
> Ветка alloc-templates в 
> http://git.altlinux.org/people/imz/packages/apt.git
> 
> (Развивая это, можно RawAllocate() превратить в какой-нибудь
> template<typename T> RawAllocateArray<T>(unsigned long ItemCount),
> там, правда, Pools нетривиально надо будет переделать.
> 
> Пришлось, правда, перенести определение из .cc в .h и патчи дальнейшие 
> неудобно прикладывать; но можно их ifdef-ами обложить в .cc и заинклудить 
> в .h.)
> 
> From 89499e5810575336e6a3b02d71d6c323321a0eca Mon Sep 17 00:00:00 2001
> From: Ivan Zakharyaschev <imz@altlinux.org>
> Date: Fri, 14 Feb 2020 04:04:42 +0300
> Subject: [PATCH] don't pass compile-time constants as an argument to
>  DynamicMMap::Allocate()
> 
> The argument was used for the size of the item we want to allocate.
> 
> Instead of an argument, use a parameter for the template DynamicMMap::Allocate()
> which denotes the type of the item.
> 
> Now, the truth of our assertion that the size is not zero is evident
> (and checked by the compiler).
> 
> Note that this change may also potentially lead to more optimized code
> due to compile-time specialization for each particular size.
> ---
>  apt/apt-pkg/contrib/mmap.h | 12 ++++++------
>  apt/apt-pkg/pkgcachegen.cc | 19 ++++++++++---------
>  apt/apt-pkg/pkgcachegen.h  |  3 ++-
>  3 files changed, 18 insertions(+), 16 deletions(-)
> 
> diff --git a/apt/apt-pkg/contrib/mmap.h b/apt/apt-pkg/contrib/mmap.h
> index 5b14ac9d9..7ec0fb8b1 100644
> --- a/apt/apt-pkg/contrib/mmap.h
> +++ b/apt/apt-pkg/contrib/mmap.h
> @@ -94,7 +94,8 @@ class DynamicMMap : public MMap
>  
>     // Allocation
>     std::experimental::optional<unsigned long> RawAllocate(unsigned long Size,unsigned long Aln = 0);
> -   std::experimental::optional<unsigned long> Allocate(unsigned long ItemSize);
> +   template<typename T>
> +   std::experimental::optional<unsigned long> Allocate();
>     std::experimental::optional<unsigned long> WriteString(const char *String,unsigned long Len = std::numeric_limits<unsigned long>::max());
>     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;};
> @@ -107,17 +108,16 @@ class DynamicMMap : public MMap
>  /* Templates */
>  
>  #include <apt-pkg/error.h>
> -#include <cassert>
>  
>  // DynamicMMap::Allocate - Pooled aligned allocation			/*{{{*/
>  // ---------------------------------------------------------------------
>  /* This allocates an Item of size ItemSize so that it is aligned to its
>     size in the file. */
> -std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize)
> +template<typename T>
> +std::experimental::optional<unsigned long> DynamicMMap::Allocate()
>  {
> -   assert(ItemSize != 0); /* Actually, we are always called with sizeof(...)
> -                             compile-time non-zero constant as the argument.
> -                          */
> +   constexpr unsigned long ItemSize = sizeof(T);
> +   static_assert(ItemSize != 0);

Давайте не закладываться на C++17:
https://en.cppreference.com/w/cpp/language/static_assert

static_assert ( bool_constexpr , message ) 	(since C++11)
static_assert ( bool_constexpr ) 		(since C++17)

Так что прошу использовать первую форму (C++11 с сообщением)
и убедится, что явно задан как минимум -std=c++11/gnu++11.

>  
>     // Look for a matching pool entry
>     Pool *I;
> diff --git a/apt/apt-pkg/pkgcachegen.cc b/apt/apt-pkg/pkgcachegen.cc
> index 4bbab07bf..2a75f31e6 100644
> --- a/apt/apt-pkg/pkgcachegen.cc
> +++ b/apt/apt-pkg/pkgcachegen.cc
> @@ -112,8 +112,9 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::WriteStringInMap(c
>     return Map.WriteString(String);
>  }
>  									/*}}}*/
> -std::experimental::optional<unsigned long> pkgCacheGenerator::AllocateInMap(unsigned long size) {/*{{{*/
> -   return Map.Allocate(size);
> +template<typename T>
> +std::experimental::optional<unsigned long> pkgCacheGenerator::AllocateInMap() {/*{{{*/
> +   return Map.Allocate<T>();
>  }
>  									/*}}}*/
>  // CacheGenerator::MergeList - Merge the package list			/*{{{*/
> @@ -376,7 +377,7 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg, const string &Nam
>  #endif
>         
>     // Get a structure
> -   const auto Package = AllocateInMap(sizeof(pkgCache::Package));
> +   const auto Package = AllocateInMap<pkgCache::Package>();
>     const auto idxName = WriteStringInMap(Name);
>     if ((!Package) || (!idxName))
>        return false;
> @@ -429,7 +430,7 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
>        return true;
>     
>     // Get a structure
> -   const auto VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
> +   const auto VerFile = AllocateInMap<pkgCache::VerFile>();
>     if (!VerFile)
>        return false;
>     
> @@ -460,7 +461,7 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::NewVersion(pkgCach
>  					    unsigned long Next)
>  {
>     // Get a structure
> -   const auto Version = AllocateInMap(sizeof(pkgCache::Version));
> +   const auto Version = AllocateInMap<pkgCache::Version>();
>     const auto idxVerStr = WriteStringInMap(VerStr);
>     if ((!Version) || (!idxVerStr))
>        return std::experimental::nullopt;
> @@ -487,7 +488,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
>     pkgCache &Cache = Owner->Cache;
>     
>     // Get a structure
> -   const auto Dependency = Owner->AllocateInMap(sizeof(pkgCache::Dependency));
> +   const auto Dependency = Owner->AllocateInMap<pkgCache::Dependency>();
>     if (!Dependency)
>        return false;
>     
> @@ -574,7 +575,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
>        }
>     }
>     // Get a structure
> -   const auto Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
> +   const auto Provides = Owner->AllocateInMap<pkgCache::Provides>();
>     if (!Provides)
>        return false;
>     /* Note:
> @@ -618,7 +619,7 @@ bool pkgCacheGenerator::SelectFile(const string &File, const string &Site,
>  				   unsigned long Flags)
>  {
>     // Get some space for the structure
> -   const auto idxFile = AllocateInMap(sizeof(*CurrentFile));
> +   const auto idxFile = AllocateInMap<decltype(*CurrentFile)>();
>     const auto idxFileName = WriteStringInMap(File);
>     const auto idxSite = WriteUniqString(Site);
>     const auto idxIndexType = WriteUniqString(Index.GetType()->Label);
> @@ -676,7 +677,7 @@ std::experimental::optional<unsigned long> pkgCacheGenerator::WriteUniqString(co
>     }
>     
>     // Get a structure
> -   const auto Item = AllocateInMap(sizeof(pkgCache::StringItem));
> +   const auto Item = AllocateInMap<pkgCache::StringItem>();
>     const auto idxString = WriteStringInMap(S, Size);
>     if ((!Item) || (!idxString))
>        return std::experimental::nullopt;
> diff --git a/apt/apt-pkg/pkgcachegen.h b/apt/apt-pkg/pkgcachegen.h
> index b789177ef..73252802b 100644
> --- a/apt/apt-pkg/pkgcachegen.h
> +++ b/apt/apt-pkg/pkgcachegen.h
> @@ -39,7 +39,8 @@ class pkgCacheGenerator
>     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);
> +   template<typename T>
> +   std::experimental::optional<unsigned long> AllocateInMap();
>  
>     public:
>     


Best regards,
Andrew Savchenko

[-- Attachment #2: Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-17 14:05       ` Andrey Savchenko
@ 2020-02-17 17:48         ` Ivan Zakharyaschev
  0 siblings, 0 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-17 17:48 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 3412 bytes --]

Hello!

On Mon, 17 Feb 2020, Andrey Savchenko wrote:

> On Mon, 17 Feb 2020 11:41:36 +0300 (MSK) Ivan Zakharyaschev wrote:
> > Появилась идея, что есть способ здесь не просто ответственность возложить 
> > на программиста на словах (вызывать Allocate() с ненулевым аргументом), но 
> > и формально предложить такой способ программирования, где не будет 
> > возможности делать не так, как задумано.
> > 
> > Да и попроще вызовы получаются.
> > 
> > Ветка alloc-templates в 
> > http://git.altlinux.org/people/imz/packages/apt.git
> > 
> > (Развивая это, можно RawAllocate() превратить в какой-нибудь
> > template<typename T> RawAllocateArray<T>(unsigned long ItemCount),
> > там, правда, Pools нетривиально надо будет переделать.
> > 
> > Пришлось, правда, перенести определение из .cc в .h и патчи дальнейшие 
> > неудобно прикладывать; но можно их ifdef-ами обложить в .cc и заинклудить 
> > в .h.)
> > 
> > From 89499e5810575336e6a3b02d71d6c323321a0eca Mon Sep 17 00:00:00 2001
> > From: Ivan Zakharyaschev <imz@altlinux.org>
> > Date: Fri, 14 Feb 2020 04:04:42 +0300
> > Subject: [PATCH] don't pass compile-time constants as an argument to
> >  DynamicMMap::Allocate()
> > 
> > The argument was used for the size of the item we want to allocate.
> > 
> > Instead of an argument, use a parameter for the template DynamicMMap::Allocate()
> > which denotes the type of the item.
> > 
> > Now, the truth of our assertion that the size is not zero is evident
> > (and checked by the compiler).
> > 
> > Note that this change may also potentially lead to more optimized code
> > due to compile-time specialization for each particular size.
> > ---
> >  apt/apt-pkg/contrib/mmap.h | 12 ++++++------
> >  apt/apt-pkg/pkgcachegen.cc | 19 ++++++++++---------
> >  apt/apt-pkg/pkgcachegen.h  |  3 ++-
> >  3 files changed, 18 insertions(+), 16 deletions(-)

> > -std::experimental::optional<unsigned long> DynamicMMap::Allocate(unsigned long ItemSize)
> > +template<typename T>
> > +std::experimental::optional<unsigned long> DynamicMMap::Allocate()
> >  {
> > -   assert(ItemSize != 0); /* Actually, we are always called with sizeof(...)
> > -                             compile-time non-zero constant as the argument.
> > -                          */
> > +   constexpr unsigned long ItemSize = sizeof(T);
> > +   static_assert(ItemSize != 0);
> 
> Давайте не закладываться на C++17:
> https://en.cppreference.com/w/cpp/language/static_assert
> 
> static_assert ( bool_constexpr , message ) 	(since C++11)
> static_assert ( bool_constexpr ) 		(since C++17)
> 
> Так что прошу использовать первую форму (C++11 с сообщением)
> и убедится, что явно задан как минимум -std=c++11/gnu++11.

Спасибо за замечание!

Я об этом просто не думал пока, хотел проиллюстрировать идею 
компилирующимся кодом (на x86_64).

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-17  8:41     ` Ivan Zakharyaschev
  2020-02-17 14:05       ` Andrey Savchenko
@ 2020-02-17 21:35       ` Dmitry V. Levin
  2020-02-17 21:58         ` Ivan Zakharyaschev
  1 sibling, 1 reply; 11+ messages in thread
From: Dmitry V. Levin @ 2020-02-17 21:35 UTC (permalink / raw)
  To: ALT Devel discussion list

On Mon, Feb 17, 2020 at 11:41:36AM +0300, Ivan Zakharyaschev wrote:
> On Thu, 13 Feb 2020, Ivan Zakharyaschev wrote:
> 
> > > > есть такой hunk касательно DynamicMMap::RawAllocate():
> > > > 
> > > > diff --git a/apt/apt-pkg/contrib/mmap.cc b/apt/apt-pkg/contrib/mmap.cc
> > > > index d7a5c3a68..36dc11524 100644
> > > > --- a/apt/apt-pkg/contrib/mmap.cc
> > > > +++ b/apt/apt-pkg/contrib/mmap.cc
> > > > @@ -226,6 +245,12 @@ unsigned long DynamicMMap::RawAllocate(unsigned long
> > > > Size,unsigned long Aln)
> > > >      size in the file. */
> > > >   unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
> > > >   {
> > > > +   if (ItemSize == 0)
> > > > +   {
> > > > +      _error->Error("Can't allocate an item of size zero");
> > > > +      return 0;
> > > > +   }
> > > > +
> > > >      // Look for a matching pool entry
> > > >      Pool *I;
> > > >      Pool *Empty = 0;
> 
> > > > Во-вторых, я подумал, что это такой класс ошибок, который не возникает
> > > > в run-time из-за плохих данных или отказа ОС (например, выделить
> > > > память или прочитать файл) -- т.е. не что-то заранее непредсказуемое
> > > > для программиста и поэтому требующее специальной обработки в run-time.
> > > > 
> > > > Если програмист написал всё так, как он хотел, то он не передаст
> > > > неправильный аргумент (0) в функцию. (Да и понятно, что в реальном
> > > > коде APT это не ожидается: там обычно этот аргумент заполняется
> > > > константой sizeof(...).)
> > > > 
> > > 
> > > Ты упускаешь большой момент. mmap.h - публичный заголовок библиотеки libapt.
> > > Помимо самого apt, им пользуется ещё и немало клиентов. Даже если в самом apt
> > > не найдётся способа неправильно вызвать данную функцию, это ничего не значит.
> > > Не проверять входные данные - плохая идея.
> > 
> > Всё равно это ответственность программиста: правильно вызвать.
> > 
> > Я выше написал, в каких случаях я счиатю нужным проверять данные.
> > 
> > > > Я бы предложил такие требования (имеющие характер спецификации того,
> > > > что программист задумал реализовать) оформлять просто с помощью
> > > > assert.
> > > > 
> > > 
> > > assert в не-debug сборке отсутствует. Потому чуть более чем полностью
> > > бесполезен не во время разработки приложения.
> > 
> > Я так и задумывал.
> > 
> > 
> > > Это не средство проверки входных
> > > данных. Поэтому я против.
> > > 
> > > > Так будет легче понимать код: сразу ясно, что выполнение этого условия
> > > > (важного для корректности кода в теле функции) просто гарантируется
> > > > тем, как весь наш код написан и вообще-то может быть обосновано ещё до
> > > > run-time (просто глядя на исходный код, на том же этапе работы, что и
> > > > запускаем компилятор).
> 
> Появилась идея, что есть способ здесь не просто ответственность возложить 
> на программиста на словах (вызывать Allocate() с ненулевым аргументом), но 
> и формально предложить такой способ программирования, где не будет 
> возможности делать не так, как задумано.
> 
> Да и попроще вызовы получаются.
> 
> Ветка alloc-templates в 
> http://git.altlinux.org/people/imz/packages/apt.git

Я всячески приветствую такой подход, и я всем советую static_assert.
Но всё же static_assert(sizeof(T) > 0, "sizeof(T) == 0")
выглядит чрезмерно пессимистичным.
Надо всё-таки очень сильно постараться, чтобы инстанцировать
pkgCacheGenerator::AllocateInMap() классом нулевого размера.


-- 
ldv


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [devel] re APT patch with impossible error on "Can't allocate an item of size zero"
  2020-02-17 21:35       ` Dmitry V. Levin
@ 2020-02-17 21:58         ` Ivan Zakharyaschev
  0 siblings, 0 replies; 11+ messages in thread
From: Ivan Zakharyaschev @ 2020-02-17 21:58 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 723 bytes --]


On Tue, 18 Feb 2020, Dmitry V. Levin wrote:

> > Да и попроще вызовы получаются.
> > 
> > Ветка alloc-templates в 
> > http://git.altlinux.org/people/imz/packages/apt.git
> 
> Я всячески приветствую такой подход, и я всем советую static_assert.
> Но всё же static_assert(sizeof(T) > 0, "sizeof(T) == 0")
> выглядит чрезмерно пессимистичным.

А я думал, это весёлая шутка.

> Надо всё-таки очень сильно постараться, чтобы инстанцировать
> pkgCacheGenerator::AllocateInMap() классом нулевого размера.

В стандартном C++, как я понял, нельзя иметь структуры нулевого размера, 
но в GNU-расширениях к C такое вроде есть, поэтому оставил на всякий 
случай, чтобы ни у кого вопросов не было (а вдруг 0?).

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-02-17 21:58 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-13  2:08 [devel] re APT patch with impossible error on "Can't allocate an item of size zero" Ivan Zakharyaschev
2020-02-13  2:43 ` Ivan Zakharyaschev
2020-02-13 12:59 ` Aleksei Nikiforov
2020-02-13 14:10   ` Ivan Zakharyaschev
2020-02-13 17:05     ` Ivan Zakharyaschev
2020-02-17  8:41     ` Ivan Zakharyaschev
2020-02-17 14:05       ` Andrey Savchenko
2020-02-17 17:48         ` Ivan Zakharyaschev
2020-02-17 21:35       ` Dmitry V. Levin
2020-02-17 21:58         ` Ivan Zakharyaschev
2020-02-13 14:51   ` Ivan Zakharyaschev

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