Вызов глобального delete из перегруженного
От: Melfis  
Дата: 09.08.10 13:57
Оценка:
Доброго времени суток. Требуется чистить отдаваемую системе память. Перегружаю глобальный оператор delete.
void __cdecl operator delete(void* ptr)
{
SecureZeroMemory(ptr,_msize(ptr));
...
}

После чистки памяти хочется вызвать обычный глобальный delete (тот что был до перегрузки).
::operator delete вызывает мой перегруженный вариант. Можно ли как то вызвать неперегруженный
вариант delete?
Re: Вызов глобального delete из перегруженного
От: uzhas Ниоткуда  
Дата: 09.08.10 14:02
Оценка: 1 (1)
Здравствуйте, Melfis, Вы писали:

M>После чистки памяти хочется вызвать обычный глобальный delete (тот что был до перегрузки).

M>::operator delete вызывает мой перегруженный вариант. Можно ли как то вызвать неперегруженный
M>вариант delete?

можно завернуть старый delete в длл, а в перегруженном delete вызывать тот, который внутри длл находится
Re: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 09.08.10 14:32
Оценка:
Здравствуйте, Melfis, Вы писали:

M>Доброго времени суток. Требуется чистить отдаваемую системе память. Перегружаю глобальный оператор delete.


Не "перегружаю", а "переписываю".
Идея на 3-. По сути, нарушается ODR, и это может аукнуться там, где компилятор проинлайнил, а также где линкер подставил исходный оператор (если рантайм в .dll)

M>После чистки памяти хочется вызвать обычный глобальный delete (тот что был до перегрузки).


Можно пойти другим путём: заодно переписать ::operator new(size_t)
И внутри этой пары new/delete вызывать собственную согласованную пару функций — например, malloc/free.
Перекуём баги на фичи!
Re[2]: Вызов глобального delete из перегруженного
От: uzhas Ниоткуда  
Дата: 09.08.10 15:14
Оценка: 64 (1)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Melfis, Вы писали:


M>>Доброго времени суток. Требуется чистить отдаваемую системе память. Перегружаю глобальный оператор delete.


К>Не "перегружаю", а "переписываю".

можно сказать "заменяю"

3.7.3 Dynamic storage duration
<skip>
2. The library provides default definitions for the global allocation and deallocation functions. Some global
allocation and deallocation functions are replaceable (18.4.1). A C + + program shall provide at most one
definition of a replaceable allocation or deallocation function. Any such function definition replaces the
default version provided in the library (17.4.3.4).

К>Идея на 3-. По сути, нарушается ODR, и это может аукнуться там, где компилятор проинлайнил, а также где линкер подставил исходный оператор (если рантайм в .dll)
В чем плохость идеи? Я так понял, что ТС хочет занулять освобожденную память. Как иначе это сделать?
ODR не нарушается и переопределение этой функции разрешено стандартом.
Re[3]: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 09.08.10 15:28
Оценка:
Здравствуйте, uzhas, Вы писали:

U>ODR не нарушается и переопределение этой функции разрешено стандартом.


Как говорится, век живи, век учись...
Остаётся вопрос, как эта штука уживается с *crt*.dll ?
Перекуём баги на фичи!
Re[4]: Вызов глобального delete из перегруженного
От: uzhas Ниоткуда  
Дата: 09.08.10 15:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Остаётся вопрос, как эта штука уживается с *crt*.dll ?

а в чем сложность?
линкер в процессе линковки смотрит:
если юзер написал свою функцию, то родной delete не линкуется
иначе линкуется
как это связано с *crt*.dll? она лишь может потянуться, если залинковали дефолтную реализацию delete
Re[5]: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 09.08.10 16:13
Оценка:
Здравствуйте, uzhas, Вы писали:

U>как это связано с *crt*.dll? она лишь может потянуться, если залинковали дефолтную реализацию delete


А в недрах *crt*.dll этот new/delete нигде не используется?

К примеру, я встречал CRT (правда, не для виндов, а для VxWorks) где были явные инстансы basic_string<char> и <wchar_t> aka string и wstring со всеми их методами. (Чтобы в каждом своём модуле не повторяться, а использовать уже готовое).
Вроде бы стандарт не запрещает делать такую оптимизированную реализацию?
Но это значит, что либо там собственный аллокатор, либо возникает обратная зависимость — CRT от пользовательского модуля.

Отсюда вывод: либо в VxWorks кривой несовместимый со стандартом CRT (охотно в это верю!), либо таки существует ограничение: в недрах crt.dll нет никаких вызовов new/delete, всё исключительно в инлайнах, пускай компилятор разбирается сам.


И второй вывод, практический: если в программе два и более модуля, то, как бы они ни использовали общий рантайм, но общий изменённый new/delete использовать у них не получится.
Максимум, что можно — это сделать идентичные определения (например, в общем хедере), устойчивые к существованию дубликатов функций (т.е. без статических переменных и т.п.)
Перекуём баги на фичи!
Re[2]: Вызов глобального delete из перегруженного
От: Melfis  
Дата: 09.08.10 17:50
Оценка:
Здравствуйте, uzhas, Вы писали:

U>можно завернуть старый delete в длл, а в перегруженном delete вызывать тот, который внутри длл находится


Вариант конечно, но не хотелось бы делать отдельную длл ради одной функции
Re[6]: Вызов глобального delete из перегруженного
От: uzhas Ниоткуда  
Дата: 09.08.10 18:24
Оценка:
Здравствуйте, Кодт, Вы писали:

К>К примеру, я встречал CRT (правда, не для виндов, а для VxWorks) где были явные инстансы basic_string<char> и <wchar_t> aka string и wstring со всеми их методами. (Чтобы в каждом своём модуле не повторяться, а использовать уже готовое).

К>Вроде бы стандарт не запрещает делать такую оптимизированную реализацию?
К>Но это значит, что либо там собственный аллокатор, либо возникает обратная зависимость — CRT от пользовательского модуля.

теперь понял о какой проблеме вы говорите
мне казалось, что в студии тоже basic_string реализован в длл (можно посмотреть на экспорты), но не знаю как включить такие строки
в дебугере проверил — в длл не уходит
ну а технически можно ведь через аллокатор вызвать юзерский delete
в первом модуле вызываем basic_string<Allocator>::erase(..); внутри crt.dll могут вызывать Allocator::deallocate, который вернется в первый модуль и вызовет там delete

кстати, задумался, а обязательно ли basic_string должен использовать оператор new?
нашел ответ

20.4.1 The default allocator
namespace std {
template <class T> class allocator;
<skip>
}

20.4.1.1 allocator members
pointer address(reference x) const;
1 Returns: &x.
const_pointer address(const_reference x) const;
2 Returns: &x.

pointer allocate(size_type n, allocator<void>::const_pointer hint=0);
3 Notes: Uses ::operator new(size_t) (18.4.1).


Header <string> synopsis
namespace std {
// 21.3, basic_string:
template<class charT, class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string;

Re: Вызов глобального delete из перегруженного
От: Melfis  
Дата: 10.08.10 06:11
Оценка:
M>Доброго времени суток. Требуется чистить отдаваемую системе память. Перегружаю глобальный оператор delete.
M>void __cdecl operator delete(void* ptr)
M>{
M> SecureZeroMemory(ptr,_msize(ptr));
M> ...
M>}

M>После чистки памяти хочется вызвать обычный глобальный delete (тот что был до перегрузки).

M>::operator delete вызывает мой перегруженный вариант. Можно ли как то вызвать неперегруженный
M>вариант delete?

Простого решения не нашлось. Может имеется какой то другой способ вклиниться в процесс освобождения памяти под release сборкой, кроме перегрузки delete?
Re[2]: Вызов глобального delete из перегруженного
От: uzhas Ниоткуда  
Дата: 10.08.10 06:55
Оценка:
Здравствуйте, Melfis, Вы писали:

M>Простого решения не нашлось. Может имеется какой то другой способ вклиниться в процесс освобождения памяти под release сборкой, кроме перегрузки delete?

напишите свой аллокатор и суйте во все stl-контейнеры =) но длл попроще сделать=) у нас в дебуге есть подобная длл, помогает нам отлавливать утечки (при выгрузке печатаются все фрагменты памяти со стеком аллокации, которые не были удалены)
Re[3]: Вызов глобального delete из перегруженного
От: Melfis  
Дата: 10.08.10 07:06
Оценка:
Здравствуйте, uzhas, Вы писали:

U>напишите свой аллокатор и суйте во все stl-контейнеры =) но длл попроще сделать=) у нас в дебуге есть подобная длл, помогает нам отлавливать утечки (при выгрузке печатаются все фрагменты памяти со стеком аллокации, которые не были удалены)


Под дебагом есть allocation hook'и, мне нужно под релизом. Аллокатор не пойдет, т.к. мне нужно очищать ВСЮ освобождаемую память.
Re[4]: Вызов глобального delete из перегруженного
От: Vain Россия google.ru
Дата: 10.08.10 09:03
Оценка:
Здравствуйте, Кодт, Вы писали:

U>>ODR не нарушается и переопределение этой функции разрешено стандартом.

К>Как говорится, век живи, век учись...
К>Остаётся вопрос, как эта штука уживается с *crt*.dll ?
А какие проблемы? *crt*.dll использует свою реализацию, ваше приложение/dll свою, имхо линкер должен это поддерживать.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[5]: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 11.08.10 07:32
Оценка:
Здравствуйте, Vain, Вы писали:

V>А какие проблемы? *crt*.dll использует свою реализацию, ваше приложение/dll свою, имхо линкер должен это поддерживать.


Дело в том, что — либо crt.dll не зависит от .exe, и использует свой комплект new/delete изолированно (интересно, где? в шаблонных аллокаторах — не имеет права, это точно создаст нарушение ODR), либо зависит — и линкер здесь бессилен, да и загрузчик тоже.
Единственный способ, как эту обратную зависимость можно воплотить — это глобальные переменные-указатели на функции. *crt*.dll их настраивает на дефолнтую реализацию, а затем .exe на свою собственную.
Перекуём баги на фичи!
Re[6]: Вызов глобального delete из перегруженного
От: Vain Россия google.ru
Дата: 11.08.10 18:44
Оценка:
Здравствуйте, Кодт, Вы писали:

V>>А какие проблемы? *crt*.dll использует свою реализацию, ваше приложение/dll свою, имхо линкер должен это поддерживать.

К>Дело в том, что — либо crt.dll не зависит от .exe
Я не совсем понимаю почему crt.dll должен зависить от кого-то, вообще это кто-то должен зависеть от него.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[7]: Вызов глобального delete из перегруженного
От: Andrew S Россия http://alchemy-lab.com
Дата: 11.08.10 19:11
Оценка:
U>теперь понял о какой проблеме вы говорите
U>мне казалось, что в студии тоже basic_string реализован в длл (можно посмотреть на экспорты), но не знаю как включить такие строки
U>в дебугере проверил — в длл не уходит
U>ну а технически можно ведь через аллокатор вызвать юзерский delete

Через стайтлесс — нельзя.

U>в первом модуле вызываем basic_string<Allocator>::erase(..); внутри crt.dll могут вызывать Allocator::deallocate, который вернется в первый модуль и вызовет там delete


Никуда он не вернется.
Ситуация с динамическими либами. Модуль А с переопределенным оператором. Модуль Б без.
Б получает из А ссылку на vector и вызывает insert. В результате используется оператор и аллокатор, определенные в модуле Б.
А поскольку удалять объект будет модуль А, то будет бабах.

В общем, надо повторять мантру — объекты нельзя передавать через границы (динамических) модулей, если они для этого не предназначены специально (например, имеют гарантии abi). Есть adobe::abi stl, вот там с некоторыми ограничениями так можно.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[7]: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 12.08.10 08:18
Оценка:
Здравствуйте, Vain, Вы писали:

V>Я не совсем понимаю почему crt.dll должен зависить от кого-то, вообще это кто-то должен зависеть от него.


Потому что по стандарту.
Если пользователь может переопределить стандартную функцию, — то это пользовательское определение должно распространиться на всю программу.
Перекуём баги на фичи!
Re[8]: Вызов глобального delete из перегруженного
От: Vain Россия google.ru
Дата: 12.08.10 11:15
Оценка:
Здравствуйте, Кодт, Вы писали:

V>>Я не совсем понимаю почему crt.dll должен зависить от кого-то, вообще это кто-то должен зависеть от него.

К>Потому что по стандарту.
К>Если пользователь может переопределить стандартную функцию, — то это пользовательское определение должно распространиться на всю программу.
Оно и распространяется, только причём здесь зависимость crt от приложения?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[9]: Вызов глобального delete из перегруженного
От: Кодт Россия  
Дата: 12.08.10 11:49
Оценка:
Здравствуйте, Vain, Вы писали:

К>>Если пользователь может переопределить стандартную функцию, — то это пользовательское определение должно распространиться на всю программу.

V>Оно и распространяется, только причём здесь зависимость crt от приложения?

Ещё раз, внимательно.

1. Пусть CRT содержит, например, скомпилированные методы специализации basic_string<char> и, соответственно, allocator<char>.
2. Пусть эти методы используют buf_ = new char[N]; / delete[] buf_;
3. Пусть пользователь переписал ::operator new[] и ::operator delete[]

Вопрос: как CRT узнает о том, что эти операторы переписаны, если оно уже скомпилировано и слинковано в crt.dll ?
Эрго,
— либо оно будет использовать свои, непереписанные, версии этих операторов (нарушаем ODR, э?)
— либо есть какой-то механизм обратного связывания, позволяющий экзешнику подсунуть переписанную версию внутрь dll
Перекуём баги на фичи!
Re[10]: Вызов глобального delete из перегруженного
От: Vain Россия google.ru
Дата: 12.08.10 12:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>>>Если пользователь может переопределить стандартную функцию, — то это пользовательское определение должно распространиться на всю программу.

V>>Оно и распространяется, только причём здесь зависимость crt от приложения?
К>Ещё раз, внимательно.
К>1. Пусть CRT содержит, например, скомпилированные методы специализации basic_string<char> и, соответственно, allocator<char>.
К>2. Пусть эти методы используют buf_ = new char[N]; / delete[] buf_;
К>3. Пусть пользователь переписал ::operator new[] и ::operator delete[]
К>Вопрос: как CRT узнает о том, что эти операторы переписаны, если оно уже скомпилировано и слинковано в crt.dll ?
Я и спрашиваю зачем CRT это узнавать, раз аллокатор уже скомпанован?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.