[devel] вопрос по языку Си - порядок вычисления операндов

Kirill A. Shutemov kirill at shutemov.name
Thu Oct 1 05:09:40 UTC 2009


2009/10/1 Kirill A. Shutemov <kirill �� shutemov.name>:
> 2009/10/1 Alexey Tourbin <at �� altlinux.ru>:
>> У нас в rpm есть такой код.
>>
>> lib/depends.h:
>>   108  typedef /*@abstract@*/ struct availableList_s {
>>   109  /*@owned@*/ /*@null@*/ struct availablePackage * list;  /*!< Set of packages. */
>>   110      struct availableIndex index;        /*!< Set of available items. */
>>   111      int delta;                          /*!< Delta for pkg list reallocation. */
>>   112      int size;                           /*!< No. of pkgs in list. */
>>   113      int alloced;                        /*!< No. of pkgs allocated for list. */
>>   114      int numDirs;                        /*!< No. of directories. */
>>   115  /*@owned@*/ /*@null@*/ dirInfo dirs;    /*!< Set of directories. */
>>   116  } * availableList;
>> ...
>>
>> lib/depends.c:
>>   213  static /*@exposed@*/ struct availablePackage *
>>   214  alAddPackage(availableList al,
>>   215                  Header h, /*@null@*/ /*@dependent@*/ const void * key,
>>   216                  /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs)
>>   217          /*@modifies al, h @*/
>>   218  {
>>   219      HGE_t hge = (HGE_t)headerGetEntryMinMemory;
>>   220      HFD_t hfd = headerFreeData;
>>   221      rpmTagType dnt, bnt;
>>   222      struct availablePackage * p;
>>   223      rpmRelocation * r;
>>   224      int i;
>>   225      int_32 * dirIndexes;
>>   226      const char ** dirNames;
>>   227      int numDirs, dirNum;
>>   228      int * dirMapping;
>>   229      struct dirInfo_s dirNeedle;
>>   230      dirInfo dirMatch;
>>   231      int first, last, fileNum;
>>   232      int origNumDirs;
>>   233      int pkgNum;
>>   234
>>   235      if (al->size == al->alloced) {
>>   236          al->alloced += al->delta;
>>   237          al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
>>   238      }
>> ...
>>   703  int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
>>   704                          const void * key, int upgrade, rpmRelocation * relocs)
>>   705  {
>>   706      HGE_t hge = (HGE_t)headerGetEntryMinMemory;
>>   707      HFD_t hfd = headerFreeData;
>>   708      rpmTagType ont, ovt;
>>   709      /* this is an install followed by uninstalls */
>>   710      const char * name;
>>   711      int count;
>>   712      const char ** obsoletes;
>>   713      int alNum;
>>   714
>>   715      /*
>>   716       * FIXME: handling upgrades like this is *almost* okay. It doesn't
>>   717       * check to make sure we're upgrading to a newer version, and it
>>   718       * makes it difficult to generate a return code based on the number of
>>   719       * packages which failed.
>>   720       */
>>   721      if (ts->orderCount == ts->orderAlloced) {
>>   722          ts->orderAlloced += ts->delta;
>>   723          ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
>>   724      }
>>   725      ts->order[ts->orderCount].type = TR_ADDED;
>>   726      if (ts->addedPackages.list == NULL)
>>   727          return 0;
>>   728
>>   729      alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
>>   730                  ts->addedPackages.list;
>>   731      ts->order[ts->orderCount++].u.addedIndex = alNum;
>> ...
>>
>> Вопрос касается строк 729-730.  Следите за движением рук.
>>
>> ts->addedPackages -- это некоторая структура данных, которая содержит
>> ts->addedPackages.list -- указатель на массив, выделяемый в куче.
>> Функция alAddPackage() добавляет новый элемент в этот массив и возвращает
>> на него указатель.  Соответственно (по правилам типизированной адресной
>> арифметики) переменная alNum -- это будет индекс последнего добавленного
>> элемента в массиве.
>>
>> Но!  Когда массив становится слишком маленьким, функция alAddPackage()
>> делает realloc этого массива (строка 237).  Соотвественно, адрес массива
>> ts->addedPackages.list может измениться.
>>
>> Теперь посмотрим на вычитание указателей в строках 729-730.  Левый
>> операнд вычитания может изменить ts->addedPackages.list, а правым
>> операндом является сам ts->addedPackages.list.  Получается, что этот
>> код зависит от порядка вычисления операндов -- а именно, может
>> использоваться либо старое значение ts->addedPackages.list, либо
>> уже новое значение.
>>
>> Воопрос соответствено насколько легален этот код, и вообще любая
>> нетривиальная информация на эту тему.
>
> ISO/IEC 9899:TC2
>
> 6.5 Expressions
>
> 3 The grouping of operators and operands is indicated by the syntax.
> Except as specified
> later (for the function-call (), &&, ||, ?:, and comma operators), the
> order of evaluation
> of subexpressions and the order in which side effects take place are
> both unspecified.
>

6.5.2.2 Function calls

12 EXAMPLE In the function call
(*pf[f1()]) (f2(), f3() + f4())
the functions f1, f2, f3, and f4 may be called in any order. All side
effects have to be completed before
the function pointed to by pf[f1()] is called


More information about the Devel mailing list