LINUX.ORG.RU

Программа крешится под Mac OS, под Linux и Win нормально. WTF?


0

1

Разрабатываю кроссплатформенную программу на Qt. Попиксельная обработка изображений через интерфейс класса QImage. И вот засада: падает при входе в рекурсивную функцию, но только на Маке. Казалось бы, стек увеличь? Увеличивал до невероятных размеров, при помощи QMAKE_LFLAGS += -Wl,-stack_size,0x10000000 - никакого влияния. Да и глубина вызовов на момент падения не такая уж большая, порядка 3000, функция лёгкая.

Диагностика: Bus error.

Не встречался никто с таким? Что бы это могло быть?

★★★★

Последнее исправление: hbee (всего исправлений: 1)
Ответ на: комментарий от Kirakishou

С чего бы? Под Linux и Windows отрабатывает со свистом.

Я с маками впервые сталкиваюсь, может, какие-то тонкости есть?

hbee ★★★★
() автор топика

>Диагностика: Bus error.

Может быть обращение к памяти по невыровненному адресу

ttnl ★★★★★
()
Ответ на: комментарий от Kirakishou

Трассировал выполнение: крешится именно при входе в функцию, до выполнения первого оператора.

hbee ★★★★
() автор топика

By default Mac OS X' (32-bit Operating System) stack size is 8192KB (8MB) and the stack storage hard limit available with the default kernel is 65536KB (64MB).

ЗЫ: если функция легкая, воспользуйтесь списком или стековым аллокатором вроде obstack

ckotinko ☆☆☆
()
Ответ на: комментарий от ttnl

Но ему неоткуда там взяться, невыровненному адресу: циклы со счётчиком int по QImage::pixel(x, y)

hbee ★★★★
() автор топика
Ответ на: комментарий от aho
/********************************************************************************
 * Recursively fill surrounding pixels of the old color.
 */
void flood_loop(QImage *raster, const int x, const int y, const QRgb fill, const QRgb old)
{
    // finds the left side, filling along the way
    int fillL (x);
    do
    {
        raster->setPixel(fillL, y, fill);
        --fillL;
    }
    while ( (fillL >= 0) && is_rgb_equal(raster->pixel(fillL, y), old) );
    ++fillL;

    // find the right right side, filling along the way
    int fillR (x);
    do
    {
        raster->setPixel(fillR, y, fill);
        ++fillR;
    }
    while ( (fillR < (raster->width() - 1)) && is_rgb_equal(raster->pixel(fillR, y), old) );
    --fillR;

    // checks if applicable up or down
    for ( int i (fillL); i <= fillR; ++i )
    {
        if ( (y > 0) && is_rgb_equal(raster->pixel(i, y - 1), old) )
        {
            flood_loop(raster, i, y - 1, fill, old);
        }
        if ( (y < (raster->height() - 1)) && is_rgb_equal(raster->pixel(i, y + 1), old) )
        {
            flood_loop(raster, i, y + 1, fill, old);
        }
    }
}
hbee ★★★★
() автор топика
Ответ на: комментарий от ckotinko

Ага, то есть больше 0x10000 не даст? Спасибо за информацию.

hbee ★★★★
() автор топика
Ответ на: комментарий от hbee

> Так я заказывал произвольный размер стека через опцию ld -stack-size.

можно попробовать задать через ulimit, чтоб проверить - в этом ли пробема

aho
()
Ответ на: комментарий от aho

Через ulimis -s hard пробовал - не помогает. Более того, не меняется глубина и т.п. А это максимум, что можно задать через ulimit.

hbee ★★★★
() автор топика
Ответ на: комментарий от hbee

создай стек с координатами пикселей, далее в цикле пока стек не пуст обрабатывай текущий пиксель, а потом клади (или не клади) в стек новые пиксели

Reset ★★★★★
()

А ты не используй в C/C++ рекурсию. Тем более не хвостовую. И в чём смысл одновременно использовать передачу по значению и константность, я не понял.

KblCb ★★★★★
()
Ответ на: комментарий от hbee

>Я с маками впервые сталкиваюсь, может, какие-то тонкости есть?

Что поддержка Apple'а говорит?

Led ★★★☆☆
()
Ответ на: комментарий от Reset

Проблема решена. Взял итеративную реализацию отсюда: http://stackoverflow.com/questions/1257117/does-anyone-have-a-working-non-rec...

Значит, всё же было переполнение программного стека. Диагностика могла бы быть и повнятнее.

hbee ★★★★
() автор топика
Ответ на: комментарий от Absurd

> Можно было и погуглить по «flood fill»

Что и было сделано :)

hbee ★★★★
() автор топика
Ответ на: комментарий от KblCb

> И в чём смысл одновременно использовать передачу по значению и константность, я не понял.

Имею привычку в C++ расставлять const где только можно. Тут смысл такой же, что и при объявлении локальной константы.

hbee ★★★★
() автор топика
Ответ на: комментарий от hbee

Ты лучше разберись с тем как переделывать рекурсивный алгоритм в итеративный. Это есть в любой книжке по программированию и алгоритмам.

Reset ★★★★★
()
void LabelComponent( unsigned char** rdesc, ptrdiff_t Width, ptrdiff_t Height,  ptrdiff_t seedx, ptrdiff_t seedy, size_t& num_points, QRectF& ResRect, const unsigned char FillID) throw()	
{
  if (!rdesc) 
    return;
  
  FillQueue queue; 
  queue.reserve(256);
  queue.push_back(FillQueue::value_type(seedx, seedy));
  
  ptrdiff_t left, top, right, bottom, clr = rdesc[seedy][seedx], x,y;

  left       = right = seedx;
  bottom     = top   = seedy;
  num_points = 0;
 
  unsigned char *currPix = 0;
  FillQueue::value_type    v;
  
  do
  {
    v = queue.back(); queue.pop_back();  
    
    x = v.first, 
    y = v.second;
    
    currPix = rdesc[y] + x;
    
    if(clr == *currPix)
    {
      *currPix = FillID; // visit current pixel 
      ++num_points;
      ++x;
      if(x < Width)
        if(rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      --x; ++y;
      if(y < Height)
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      --x; --y;
      if(x >= 0)
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      ++x; --y;
      if(y >= 0)
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      ++x;
      if( (y >= 0) && (x < Width))
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      x -= 2; y += 2;
      if((y < Height) && (x >= 0))
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      x += 2;
      if((y < Height) && (x < Width))
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
      x -= 2; y -=2;
      if((y >= 0) && (x >= 0))
        if( rdesc[y][x] == clr )
        {
          if(x > right)  right  = x;
          if(x < left)   left   = x;
          if(y > bottom) bottom = y;
          if(y < top)    top    = y;
          
          queue.push_back(FillQueue::value_type(x, y));
        }
    }
  } while(!queue.empty());
  
  ResRect.setRect(left, top, right - left + 1.f, bottom - top + 1.f);
}

rdesc - массив указателей на начало строки, подразумевается 1 пиксель == 1 байт, остальное - самостоятельно.

nikitos ★★★
()
Ответ на: комментарий от nikitos

Что-то ты размахнулся. «Широк русский человек, у бы сузил» :)

void flood_fill(uchar *raster, const int bytes_per_line, const int w, const int h,
                QPoint p, const QRgb fill, const QRgb seed)
{
    int x (p.x());
    int y (p.y());

    if ( x < 0 || x > (w - 1) || y < 0 || y > (h - 1) )
        return;

    std::stack<QPoint> stack;
    stack.push(p);
    while ( !stack.empty() )
    {
        p = stack.top();
        stack.pop();
        x = p.x();
        y = p.y();
        if ( x < 0 || x > (w - 1) || y < 0 || y > (h - 1) )
            continue;
        QRgb *scan_line = reinterpret_cast<QRgb *>(raster + y * bytes_per_line);
        const QRgb c (scan_line[x]);
        if ( is_rgb_equal(c, seed) )
        {
            scan_line[x] = fill;
            stack.push(QPoint(x + 1, y));
            stack.push(QPoint(x - 1, y));
            stack.push(QPoint(x, y + 1));
            stack.push(QPoint(x, y - 1));
        }
    }
}
hbee ★★★★
() автор топика
Ответ на: комментарий от hbee

1. У меня заливка в окрестности 8-ми точек, у вас - 4-х ;), ну и содержащий прямоугольник я считаю зачем-то ;) 2. вы потенциально добавляете на стек уже посещённые точки, от того он разбухает ;).

nikitos ★★★
()
Ответ на: комментарий от hbee

в начало функции добавить

    if ( is_rgb_equal(fill, seed) )
        return;

инчае зависания

hbee ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.