[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