IPP bugs: FloodFill
2007-11-01 17:19![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
У Intel’а есть замечательная библиотека Performance Primitives, в которой реализована куча всяких интересных функций работы с одномерными и двумерными массивами. За одномерные массивы отвечает подбиблиотека Signal Processing Library, а за двумерные — Image Processing Library.
Бо́льшую часть времени эти функции работают как описано. Но когда оно не работает, это жопа.
Вчера ковырялся в одном таком случае. Внешние симптомы: программа Грохается на ровном месте. Долбаггер показывает на совершенно невинную строчку.
Надеваем ОВЗК и ныряем в дизассемблер.
Выясняется, что кроме всего прочего в этой строчке деструктируется одна такая внутренняя картинка. Деструктор вызывает ippiFree
, ippiFree
вызывает ippsFree
, ippsFree
вызывает free
из сишного рантайма. free
падает.
Какого хрена?
Прогоняем ещё раз, внимательно следя за вершиной стека. В ippiFree
и ippsFree
приходит нормальное значение 0x01087020
, а в free
— какое-то левое 0x20087008
, чем-то неуловимо похожее на исходное, но другое. И в совсем другом месте адресного пространства.
Смотрим внимательнее. ippsFree
смотрит на 4 байта вниз от начала блока и передаёт в free
адрес, записанный там. То есть ippsAlloc
, выделяя память, выделяет немного больше того, что запрошено, чтобы обеспечить правильное выравнивание, и кладёт адрес всего блока по смещению -4
. И вот этот адрес оказывается испорчен.
Прокручиваю всё несколько раз, от места рождения блока (где по смещению -4
лежит 0x01087008
). После очередной детализации оказывается, что байт портится в вызове ippiFloodFill_8Con_8u_C1IR
. (Эта функция берёт пиксел с заданными координатами и разливает от него краску по одноцветной области.) В данном случае область состоит из одной-единственной точки в правом нижнем углу картинки. И, сюрприз, заливается как раз значением 0x20
.
Аккуратно проверяю все параметры. Нет, размер картинки задан верно, указатель на буфер тоже, по всем признакам портиться ничего не должно.
Запускаю тестовый tool. Создаю картинку. Указываю однопиксельный блок в середине и командую залить его. Смотрю под лупой — залито два пиксела, один там, где просили, а второй — строго под ним.
Вот и разгадка. При высоте 1 краска проливается на пиксел ниже, без проверки на границу массива. И это мне тут так свезло, что там оказался как раз старший байт адреса, и его значение как раз совпало со старым значением заливаемой области. А мог ведь попасть в заголовок кучи или даже в соседний блок.
Это в старинной версии 3.0. В свежей 5.2 — заливается ровно то, что нужно, но только значением 0. Или это тестовое приложение барахлит.
no subject
Date: 2007-11-01 12:41 (UTC)байтапиксела :)