Как отследить ошибку «двойное освобождение или повреждение»

С эмуляцией карт на базе хоста (HCE) в Android 4.4 вы можете эмулировать протокол ISO / IEC 14443-4. Более конкретно, вы можете эмулировать структуры приложений в соответствии с ISO / IEC 7816-4 (при этом приложения эмуляции карт должны выбираться с помощью AID). Кроме того, API не дает вам никаких средств, чтобы указать, следует ли использовать эмуляцию карты с использованием протокола типа A или типа B.

. Что касается эмуляции различных протоколов MIFARE:

  • Протокол MIFARE Ultralight (и дериватов) работает поверх ISO / IEC 14443-3.
  • Протокол MIFARE Classic частично работает поверх ISO / IEC 14443-3 (с некоторым другим обрамлением) , Таким образом, его также невозможно эмулировать MIFARE Classic с помощью Android HCE.
  • Протоколы MIFARE DESFire работают поверх ISO / IEC 14443-4. Существует три варианта протокола DESFire: собственный протокол : поскольку этот протокол не использует APDU в соответствии с ISO / IEC 7816-4, его невозможно эмулировать с помощью Android HCE. обернул собственный протокол : этот протокол использует APDU в соответствии с ISO / IEC 7816-4, однако, как правило, читатели не выдают команду SELECT с использованием DESFire AID при запуске связи с картой в оболочном режиме командной строки , (Примечание. Более новые реализации читателей с большей вероятностью выдают команду SELECT, совместимую с Android HCE, поскольку это также необходимо для некоторых новых продуктов смарт-карт NXP с эмуляцией протокола DESFire.) Протокол ISO : этот протокол основан на ISO / IEC 7816-4 и использует выбор приложений с помощью AID. Таким образом, можно будет эмулировать этот протокол с помощью Android HCE. Некоторым читателям могут потребоваться определенные значения параметров в нижних слоях протокола (например, конкретный каскадный уровень UID, определенное значение ATQA, определенное значение SAK или определенное ATS). Android HCE не имеет никаких средств для установки этих значений. См. Редактирование функциональности эмуляции гостевой карты в Android для возможного подхода к изменению этих значений для определенных корневых устройств и мой ответ на эмуляцию карты на основе хоста с идентификатором фиксированной карты для стратегия для программного изменения этих значений в пользовательском ПЗУ.

Примечание о функции HCE, доступной в CyanogenMod с версии 9.1 до версии 10.2 : Это будет подражать любому ISO / IEC 14443-4 без требования к структуре приложения в соответствии с ISO / IEC 7816-4. Вы даже можете выбрать, хотите ли вы эмулировать протокол типа A или типа B. Поэтому должно быть возможно (хотя я еще не тестировал), чтобы подражать любому из трех протоколов DESFire. Однако даже с функцией HCE CyanogenMod невозможно эмулировать протоколы MIFARE Ultralight или Classic. Более того, также невозможно влиять на параметры протокола низкого уровня, такие как UID, ATQA, SAK или ATS.

67
задан Raedwald 6 December 2018 в 13:13
поделиться

5 ответов

Если вы используете glibc, вы можете установить переменную окружения MALLOC_CHECK_ в 2, это заставит glibc использовать устойчивую к ошибкам версию malloc, которая заставит вашу программу прерваться в точке, где выполняется double free.

Вы можете установить это из gdb, используя команду set environment MALLOC_CHECK_ 2 перед запуском вашей программы; программа должна прерваться, при этом вызов free() будет виден в бэктрейсе.

см. страницу man для malloc() для получения дополнительной информации

54
ответ дан 24 November 2019 в 13:24
поделиться

Используете ли вы интеллектуальные указатели, такие как Boost shared_ptr ? Если да, проверьте, используете ли вы где-нибудь напрямую необработанный указатель, вызвав get () . Я обнаружил, что это довольно распространенная проблема.

Например, представьте сценарий, в котором исходный указатель передается (например, в качестве обработчика обратного вызова) в ваш код. Вы можете назначить это умному указателю, чтобы справиться с подсчетом ссылок и т. Д. Большая ошибка: ваш код не владеет этим указателем, если вы не сделаете глубокую копию. Когда ваш код завершится с помощью интеллектуального указателя, он уничтожит его и попытается уничтожить память, на которую он указывает, поскольку он думает , что он никому больше не нужен, но вызывающий код будет затем попробуйте удалить его, и вы получите двойную бесплатную проблему.

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

int main(int argc, char* argv[])
{
    char* ptr = new char[20];

    delete[] ptr;
    ptr = 0;  // Comment me out and watch me crash and burn.
    delete[] ptr;
}

Edit: изменено delete на delete [] , поскольку ptr - это массив символов.

4
ответ дан 24 November 2019 в 13:24
поделиться

Есть как минимум две возможные ситуации:

  1. вы удаляете одну и ту же сущность дважды
  2. вы удаляете что-то, что не было выделено

Для первого варианта я настоятельно рекомендую NULL-ить все удаленные указатели.

У вас есть три варианта:

  1. перегрузить new и delete и отслеживать выделения
  2. да, используйте gdb - тогда вы получите обратную трассировку вашего падения, и это, вероятно, будет очень полезно
  3. как уже было сказано - используйте Valgrind - в него не так просто попасть, но это сэкономит вам время в тысячу раз в будущем...
25
ответ дан 24 November 2019 в 13:24
поделиться

Три основных правила:

  1. Установить указатель на NULL после освобождения
  2. Проверить на NULL перед освобождением.
  3. Инициализировать указатель на NULL в начале работы.

Комбинация этих трех способов работает достаточно хорошо.

17
ответ дан 24 November 2019 в 13:24
поделиться

Вы можете использовать gdb, но сначала я бы попробовал Valgrind . См. руководство по быстрому запуску .

Вкратце, Valgrind настраивает вашу программу таким образом, чтобы она могла обнаруживать несколько видов ошибок при использовании динамически выделяемой памяти, таких как двойное освобождение и запись после конца выделенных блоков памяти (что может привести к повреждению кучи). Он обнаруживает и сообщает об ошибках , как только они возникают , тем самым указывая вам непосредственно на причину проблемы.

20
ответ дан 24 November 2019 в 13:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: