yurikhan: (Default)
[personal profile] yurikhan

(Ранее по теме: 1, 2, 3, 4)

У 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. Или это тестовое приложение барахлит.

Date: 2007-11-01 12:41 (UTC)
From: [identity profile] obake-neko.livejournal.com
История одного байта пиксела :)

Profile

yurikhan: (Default)
Yuri Khan

August 2018

S M T W T F S
   1234
567891011
12131415161718
19202122232425
26 2728293031 

Links

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated 2025-06-17 02:26
Powered by Dreamwidth Studios