[devel] вопрос по языку Си - порядок вычисления операндов
Alexey Tourbin
at at altlinux.ru
Thu Oct 1 01:24:28 UTC 2009
У нас в 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, либо
уже новое значение.
Воопрос соответствено насколько легален этот код, и вообще любая
нетривиальная информация на эту тему.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.altlinux.org/pipermail/devel/attachments/20091001/e409df1a/attachment-0001.bin>
More information about the Devel
mailing list