Убрать никогда не запускаемый вызов шаблонной функции, получить ошибку выделения во время выполнения - PullRequest
0 голосов
/ 27 апреля 2010

У меня есть фрагмент шаблонного кода, который никогда не запускается, но компилируется. Когда я его удаляю, другая часть моей программы ломается.


Во-первых, я немного растерялся относительно того, как задать этот вопрос. Поэтому я попытаюсь дать много информации о проблеме.

Итак, я решил полностью перепроектировать мой тестовый проект для своей экспериментальной библиотеки ядра. Я использую много шаблонных махинаций в библиотеке. Когда я удалил «пользовательский» код, тесты дали мне ошибку выделения памяти. После долгих экспериментов я сузил его до следующего кода (из пары сотен строк):

void VOODOO(components::switchBoard &board) {   
     board.addComponent<using_allegro::keyInputs<'w'> >();
}

Фундаментально, что меня удивляет, так это то, что кажется, что компиляция этой функции (и функции шаблона, которую она затем использует, и функций шаблона, которые затем используют ...), делает эту ошибку не появляются Этот код не запускается . Подобный код (тот же, но для разных значений ключа) встречается в другом месте, но находится внутри кода Boost TDD.

Я понимаю, что, конечно, я не дал достаточно информации, чтобы вы могли решить ее для меня; Я пытался, но это более или менее вписывается в большую часть кода. Я думаю, что больше всего ищу «вот в чем проблема», «здесь, где искать» и т. Д. Во время компиляции происходит что-то из-за этой строки, но я недостаточно знаю об этом шаге, чтобы начать искать .

О-о-о-о, как (предположительно) скомпилированный, но фактически никогда не запущенный бит шаблонного кода, после удаления вызвать сбой другой части кода?


Ошибка:

Unhandled exceptionat 0x6fe731ea (msvcr90d.dll) in Switchboard.exe:
0xC0000005: Access violation reading location 0xcdcdcdc1.

CallStack:

operator delete(void * pUser Data)
allocator< class name related to key inputs callbacks >::deallocate
vector< same class >::_Insert_n(...)
vector< " " >::insert(...)
vector<" ">::push_back(...)

Похоже, что вектор неверен, потому что _MyFirst и подобные члены данных показывают значения 0xcdcdcdcd в отладчике. Но вектор является переменной-членом ...

Обновление: вектор недействителен, потому что он никогда не был создан. Я получаю Stomp значения идентификатора канала, что заставляет меня рассматривать один тип канала как другой.


Обновление:

Повторный поиск с помощью отладчика, похоже, что мой метод присвоения каждому «каналу» собственного уникального идентификатора не дает мне уникальный идентификатор:

inline static const char channel<template args>::idFunction() {
    return reinterpret_cast<char>(&channel<CHANNEL_IDENTIFY>::idFunction);
};

Обновление 2: эти два дают одно и то же:

slaveChannel<switchboard, ALLEGRO_BITMAP*, entityInfo<ALLEGRO_BITMAP*>
slaveChannel<key<c>, char, push<char>

Оооо, имеет смысл менять другой скомпилированный тип канала, потому что он сдвигается вокруг значений idFunctions? Но почему существуют две idFunctions с одинаковым значением?

Ответы [ 2 ]

3 голосов
/ 27 апреля 2010

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

2 голосов
/ 27 апреля 2010

В качестве общего ответа (хотя на это ссылается aaa): когда что-то подобное влияет на возникновение ошибки, это либо потому, что (а) вы не правы и ее запускают, либо (б) способ, которым включение этого кода влияет на ваш код, данные и структуру памяти в скомпилированной программе, что приводит к изменению heisenbug с видимого на скрытый.

Последнее обычно происходит, когда что-то подразумевает неопределенное поведение. Иногда фиктивное значение указателя заставит вас растоптать немного вашего кода (что может или не может быть важным в зависимости от компоновки кода), или иногда фиктивная запись скомпрометирует значение в вашем стеке данных, которое может или не может быть быть указателем, который будет использован позже или тому подобное.

В качестве простого примера, предположим, что у вас есть стек, который выглядит следующим образом:

float data[10];
int never_used;
int *important pointer;

А потом ты ошибочно пишешь

data[10] = 0;

Затем, предполагая, что стек выделен в линейном порядке, вы наступите на never_used, и ошибка будет безвредной. Однако, если вы удалите never_used (или измените что-то, чтобы компилятор знал, что он может удалить его для вас - может быть, вы удалите никогда не вызываемый вызов функции, который будет его использовать), тогда он вместо этого будет нажимать на important_pointer, и теперь вы получите segfault, когда вы разыграете его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...