[devel] вопрос по языку Си - порядок вычисления операндов
Kharitonov A. Dmitry
kharpost at rambler.ru
Thu Oct 1 08:31:39 UTC 2009
Alexey Tourbin wrote:
> У нас в 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, либо
> уже новое значение.
>
> Воопрос соответствено насколько легален этот код, и вообще любая
> нетривиальная информация на эту тему.
>
Неоднократно натыкался на такое:
исходное выражение а+b+c
менялся порядок вычисления случайным образом
то так
а+(b+c)
то так
(а+b)+c
то так
(с+b)+a
естественно получалась случайно работающая программа. Багу ловил 3 месяца.
Во всех руководствах написано, что расстановка скобок принудительно
должна обеспечивать порядок вычислений, но я опять таки натыкался на
отступления и от этого. Разбивание выражения с применением промежуточной
переменной однозначно определяло порядок, именно тот, который мне нужен.
Промежуточная переменная в конечном коде в результате оптимизации исчезала.
Так же трудно уловимый баг связан с подстановкой в аргументы функции
скрытых временных особенно, если эти аргументы помеченны модификатором
const.
More information about the Devel
mailing list