Замена libstdc ++. Dylib (4.0) глобальных операторов new и delete в OSX - PullRequest
3 голосов
/ 13 августа 2010

Я стараюсь заменить глобальные операторы new и delete на XCode 3.2, GCC 4.2, libstdc ++ 4.0, динамическую версию.

Я взял прототипы прямо из заголовка «new» и реализовал их.Они наклеены ниже.

Проект является .plugin, поэтому динамическая библиотека.Этот плагин ДОЛЖЕН делегировать распределение собственным процедурам alloc / free основного приложения, которые находятся в старом C SDK.

Все мои собственные вызовы new / delete вместе с распределениями std :: list и std :: map корректно заменены, НО только когда std :: vector :: push_back должен увеличить свой буфер.В этом случае мой оператор new не вызывается, а оператор удаления -.Я знаю это, потому что я записываю токен в первые четыре байта любого буфера, выделенного моим новым оператором, и проверяю этот токен в операторе delete.Ниже приведен код ошибки.

extern "C++"
{
__attribute__((visibility("default"))) void* operator new(std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void* operator new[](std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void operator delete(void*) throw();
__attribute__((visibility("default"))) void operator delete[](void*) throw();
__attribute__((visibility("default"))) void* operator new(std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void* operator new[](std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete(void*, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete[](void*, const std::nothrow_t&) throw();

}

Следующий код вызовет утверждение, когда "yo" выходит из области видимости, поскольку память, выделенная для std :: vector, не была выделена моим оператором new.

   {
        std::vector<std::string> yo;
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

Следующий код в порядке, потому что std :: vector :: reserve вызывает мой оператор new:

   {
        std::vector<std::string> yo;
        yo.reserve(4);
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

GBD (отладчик) не позволит встретиться шагу с std :: vectorРеализация :: push_back, когда необходимо увеличить буфер (метод называется _M_insert_aux).Все, что я знаю, это то, что мой оператор new никогда не вызывается из std :: vector :: push_back.

Обходное решение не может быть применено ко всем сторонним библиотекам, которые я использую.Один из них - большой пользователь push_back.

Я пытался статически связываться с libstdc ++. A, но у меня та же проблема.

Есть ли какая-то специализация для std :: vector , в которой не используется глобальный оператор new?

Кстати, это отлично работает на окнах с VS9.

Ответы [ 4 ]

1 голос
/ 13 августа 2010

Я наконец-то решил свою проблему, используя технику Джорджа Костанзы: поступил наоборот.

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

  • Установить C ++ Стандартный тип библиотеки: Статический
  • Символы, скрытые по умолчанию: отмечен
  • Исправить и продолжить: Отключено (очень важно, в противном случае молча отключите предыдущую настройку)

и выполните очистку all & build, потому что в XCode 3.2 простое нажатие кнопки «Сборка» после изменения этих настроек не будет работать.Я изменил оператор new & delete прототипов на:

#pragma GCC visibility push(hidden)

extern "C++"
{
    void* operator new(std::size_t) throw (std::bad_alloc);
    void* operator new[](std::size_t) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void operator delete[](void*) throw();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();
} // extern "C++"

#pragma GCC visibility pop

Нет, почему это работает?Должны работать оба статических + скрытые символы.Кажется, он защищает мой плагин комплекта от реализаций специализаций STL, которые указали свои распределители.

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

0 голосов
/ 13 августа 2010

_M_insert_aux в vector.tcc, что, к сожалению, не очень хорошо работает с GCC. Однако быстрое сканирование показывает, что он правильно вызывает распределитель, как и другие методы.

  pointer __new_start(this->_M_allocate(__len));

Вы можете попытаться установить точку останова в вашем operator new, определить пользовательский распределитель (вы можете получить из std::allocator), который печатает выходные данные отладки, или установить точку останова в new_allocator.h:91, где библиотека должна вызвать ваше переопределение.

0 голосов
/ 13 августа 2010

Наиболее вероятным объяснением является то, что внутренняя реализация std :: vector в GCC включает в себя дополнительные перегрузки new. MSVC имеет много дополнительных операторов новых перегрузок. Вам нужно будет разорвать исходный код или создать новый пользовательский распределитель.

0 голосов
/ 13 августа 2010

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

http://www.cplusplus.com/reference/std/memory/allocator/

Мне кажется, я помню, когда смотрел на GC Hans-Bohen для C ++, что библиотека заменит new / delete на версию GC, но вам все равно пришлось передать распределитель структурам STL, которые вы хотели использовать. *

Кроме того, в библиотеках, которые вы используете, может быть код, все еще использующий malloc. О чем подумать.

...