прерывистый EXC_BAD_ACCESS в функции статического аудио-анализа - PullRequest
2 голосов
/ 31 января 2012

Я пишу приложение для iOS, которое использует анализ живого аудио.У него прерывистый сбой (через ~ 5 минут, только на симуляторе. Хотя это означает, что это не имеет значения для приложения доставки, оно, безусловно, является проблемой для разработки, и, кроме того, я буду спать лучше ночью, если буду отслеживать егоdown. Сбой всегда происходит в одном и том же месте, в статической функции в моем коде аудио-анализа: Сбой произошел здесь:

struct Tone {
// (other stuff)

// THIS is the problem function:
static bool dbCompare(Tone const& l, Tone const& r) { return l.db < r.db; }
  }
};

А также здесь:

Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const {
    if (m_tones.empty()) { m_oldfreq = 0.0; return NULL; }
    double db = std::max_element(m_tones.begin(), m_tones.end(), Tone::dbCompare)->db;
    Tone const* best = NULL;
    double bestscore = 0;
    for (tones_t::const_iterator it = m_tones.begin(); it != m_tones.end(); ++it) {

    // ON THIS LINE. Is my iterator somehow becoming invalid?:
        if (it->db < db - 20.0 || it->freq < minfreq || it->age < Tone::MINAGE) continue;
        if (it->freq > maxfreq) break;
        double score = it->db - std::max(180.0, std::abs(it->freq - 300.0)) / 10.0;
        if (m_oldfreq != 0.0 && std::fabs(it->freq/m_oldfreq - 1.0) < 0.05) score += 10.0;
        if (best && bestscore > score) break;
        best = &*it;
        bestscore = score;
    }
    m_oldfreq = (best ? best->freq : 0.0);
    return best;
}

(Хорошо, это исправление, приведенное ниже, неверно для @Justin. Я оставляю его здесь для полноты, по крайней мере, сейчас). В попытке выжить из любых нулевых указателей, которыеможет быть передан, я добавил несколько проверок и попыток обработки ошибок:

struct Tone {
    static bool dbCompare(Tone const& l, Tone const& r) {
    try {
      if (&l == NULL || &r == NULL) throw 1;
      return l.db < r.db;
      throw 1;
    }
    catch(int e) {
      NSLog(@"AUDIO ERROR: Pointer invalid. %d", e);
    }
    return 0;
  }
};

Никаких кубиков, по-прежнему не получается в той же строке. Я неправильно понимаю try-catch-throw? Ошибка только происходитдальше по конвейеру?

Этот фрагмент кода взят из игры с открытым исходным кодом в стиле рок-группы Performous , и в их игре такой проблемы нет (такжедля iPhone.) Так что это дает мне надежду, что я могуи устранить сбой симулятора ...

РЕДАКТИРОВАТЬ 2 Per @Justin Я работаю с GuardMalloc.Simulator 5.0 дает немедленный сбой - кажется, есть некоторые SO вопросы по этому поводу , но сейчас я использую симулятор 4.3, который дает сбой обычным способом, но больше ничего я не знаю, как использовать:

#0  0x94f38c97 in malloc_error_break ()
#1  0x94efa4ce in szone_error ()
#2  0x94efc35f in allocate_pages ()
#3  0x94f013cc in allocate_pages_securely ()
#4  0x94f019b8 in szone_malloc_should_clear ()
#5  0x94f0266b in szone_malloc ()
#6  0x00331cc3 in GMmalloc_zone_malloc ()
#7  0x94f38edb in malloc_set_zone_name ()
#8  0x94f394a8 in _malloc_initialize ()
#9  0x94f3986b in malloc ()
#10 0x00002ef0 in start ()
#11 0x00013f1d in std::_List_const_iterator<Tone> std::max_element<std::_List_const_iterator<Tone>, bool (*)(Tone const&, Tone const&)>(std::_List_const_iterator<Tone>, std::_List_const_iterator<Tone>, bool (*)(Tone const&, Tone const&)) at /Developer/of_007_iphone/apps/cwi007/SingXO/SingXO/Pitch/pitch.hh:25
#12 0x000139b2 in Analyzer::findTone(double, double) const ()
#13 0x00011950 in -[AppDelegate timerCallback:] ()
#14 0x00115308 in -[CCTimer update:] ()
#15 0x0011e124 in -[CCScheduler tick:] ()
#16 0x0014993a in -[CCDirectorIOS drawScene] ()
#17 0x0014bda4 in -[CCDirectorDisplayLink mainLoop:] ()
#18 0x007baa88 in CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) ()
#19 0x007babcd in CA::Display::EmulatorDisplayLink::callback(__CFRunLoopTimer*, void*) ()
#20 0x019c88c3 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#21 0x019c9e74 in __CFRunLoopDoTimer ()
#22 0x019262c9 in __CFRunLoopRun ()
#23 0x01925840 in CFRunLoopRunSpecific ()
#24 0x01925761 in CFRunLoopRunInMode ()
#25 0x020bb1c4 in GSEventRunModal ()
#26 0x020bb289 in GSEventRun ()
#27 0x00beac93 in UIApplicationMain ()
#28 0x00002fb6 in main ()

Я также получаю это в консоли:

GuardMalloc[MyApp-723]: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

О, и, конечно, вот функция, которая СЕЙЧАС кажется вероятным виновником:

- (void)timerCallback:(NSTimer *)timer {
  Tone const * tone = audio->analyzer->findTone();
  if (tone && tone->db > kToneMinDB) {
    self.currentPitch = tone->freq;
    self.currentVolume = tone->stabledb;
    self.currentNoteName = [NSString stringWithCString:scale->getNoteStr(tone->freq).c_str() encoding:NSUTF8StringEncoding];
//    NSLog(@"Current Note Name in timerCallback: %@", currentNoteName);
    self.currentNoteFunction = [pitchFilter getPitchFunctionFromPitchName:currentNoteName];
  } else {
    self.currentNoteName = @"--";
    self.currentNoteFunction = -1;
  }

}

Я не понимаю, как программа входит в блок if (tone) без действительного тона или, наоборот, как он может произойти сбой, если тональный сигнал действителен.Помогите?

(Это становится длинным. Должен ли я удалить некоторые из них в целях более сфокусированного вопроса?)

Вещи, о которых я думаю: 1. Это проблема с многопоточностью:: shudder ::, где один поток изменяет аудиоданные, в то время как другой читает их.2. Что-то в функции timerCallback портит, я не знаю, стек, потому что он слишком часто выделяется.Эта функция вызывается много, но не слишком много;это запланировано на каждые 150 мс.

Не уверен, почему любой из них будет проблемой в симуляторе, но не на устройстве.

Ответы [ 2 ]

1 голос
/ 31 января 2012

Строка best = & * it выглядит для меня странно.Контейнер хранится по ссылке или по значению?Похоже, вы возвращаете адрес временного хранилища.Это может вызвать проблемы в будущем.

1 голос
/ 31 января 2012

Ссылка на C ++ никогда не может быть 0 / NULL.Если бы это было так, вы уже хорошо знакомы с Undefined Territory.Вам придется переместить ваши тесты вверх в цепочке выполнения, если параметры могут быть 0.

То есть, единственная правильно сформированная версия dbCompare выглядит следующим образом:

struct Tone {
    static bool dbCompare(Tone const& l, Tone const& r) {
        return l.db < r.db;
    }
};

Обновление

Ваш итератор был бы недействительным, если он был изменен во время итерации - я не вижу, чтобы это происходило в этой реализации.Вы изменяете размер контейнера из другого потока?

Также попробуйте запустить его с GuardMalloc - он призван сделать эти проблемы очевидными для вас.Если произойдет сбой раньше, он будет более локальным для реализации (во многих случаях).

...