Re[5]: выделение памяти
От: ononim  
Дата: 19.08.10 14:03
Оценка: :))) :)
PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.
А я помню такой случай. Но не надо о грустном.
Как много веселых ребят, и все делают велосипед...
Re[7]: выделение памяти
От: Sergey Chadov Россия  
Дата: 21.08.10 11:04
Оценка: 1 (1) :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Sergey Chadov, Вы писали:


SC>>Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций

E>А хрен ли она не read-only? Типа из-за настройки адресов при загрузке?

А хрен-ли ей быть рид-онли?


struct A{
    virtual void M1(){
        printf("M1\n");
    }
    virtual void M2(){
        printf("M2\n");
    }
};

int main(int argc, char* argv[])
{
    A* a = new A;
    a->M1();
    *((int*)a)+=4;
    a->M1();
    return 0;
}
Re[6]: выделение памяти
От: Erop Россия  
Дата: 20.08.10 09:34
Оценка: -1 :)
Здравствуйте, Sergey Chadov, Вы писали:

SC>Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций

А хрен ли она не read-only? Типа из-за настройки адресов при загрузке?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: выделение памяти
От: Кодт Россия  
Дата: 20.08.10 14:53
Оценка: +1 :)
Топикстартер, наверно, обалдевает — как такой простой и невинный вопрос спровоцировал старожилов на флейм с мордобоем
Перекуём баги на фичи!
Re[3]: выделение памяти
От: Кодт Россия  
Дата: 19.08.10 13:42
Оценка: +1
Здравствуйте, piero_, Вы писали:

_>access vialation

_>нет все впрорядке, что значит кучу растерять? может как-то подругому выделять память?

Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.
После этого ни new[], ни malloc() работать по-нормальному уже не смогут, и будут непредсказуемо глючить.

Если в данном месте все переменные выглядят нормально, а new[], тем не менее, говорит AV — то 99%, что это плоды давнишнего расстрела.
Перекуём баги на фичи!
Re[7]: выделение памяти
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 06:55
Оценка: +1
Здравствуйте, McSeem2, Вы писали:

ТКС>>Я однажды по молодости такую херь чуть ли не неделю ловил...


MS>Для этого существуют отладочные средства. Например, я специально сделал такое против пропарывания памяти. Идея простая — на каждый alloc аллокируется как минимум одна физическая страница в 4K и аллокация размещается в самом конце блока. А после блока должна быть незамапированная страница, обращение к которой мгновенно вызывает падение. Поскольку Интел вполне может работать с невыровненными данными (хоть и тормозно), такой фокус прокатывает. Да, по отжиранию памяти и тормозам — жесткая жесть, но зато виновник определяется мгновенно, в отличие от репортов Микрософтовского аллокатора. Заодно, с очень хорошей вероятностью, ловится обращение к освобожденной памяти даже на чтение — вот это то, что никакой аллокатор не способен отловить. Чтобы повысить вероятность успешного отлова, все доступное адресное пространство работает в закольцованном режиме. Фрагментация, тормоза, отжирание памяти дикие, да. Но зато проблема находится очень быстро.


Мы вообще-то уже про порчу стека терли А с хипом самое полезное средство из MS'овских — отладочный флаг, запрещающий возврат освобожденного блока в хип. В многопоточных программах с фоновой активностью помогает радикально.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 08:26
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.

E>Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе

Уф... Ты то и дело совершаешь открытия, за которые я двойку бы поставил студентам, если бы вообще ставил какие-то оценки.

Цитирую себя. И выделяю.

PD>То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.И про расстрел статических данных я тоже что-то не помню.


Возможный расстрел стека я описал подробно. Расстрел статических данных — коротко, в надежде, что читающий поймет, что порча статических данных входит под понятие "расстрел" как я его тут употребляю.
Для этого совсем не требуется освобождать их — вполне достаточно записать по левому указатель. Если он случайно показывает внутрь стека — будет расстрел стека, если внутрь статических данных — ни с того ни с сего изменится значение некоей глобальной или статической в функции переменной.

Кстати, стек совсем не так просто устроен, как тебе кажется, и его storage (в смысле коммитированной памяти в Windows) тоже никогда не освобождается, когда стек уменьшается. Другое дело, что эта память, хоть и остается коммитированной, не принадлежит собственно стеку (принадлежит только региону стека потока)


E>Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.


E>Ну и ещё надо понимать, что стек относительно небольшой, кстати. Но в большинстве программ и куча небольшая, по сравнению с адресным пространством.


И что же в итоге ? Стек небольшой, куча небольшая, стек расстреливают редко, кучу часто. В чем тут аргументы — пойди пойми.
With best regards
Pavel Dvorkin
Re[9]: про расстрелы разных storages
От: Erop Россия  
Дата: 20.08.10 09:39
Оценка: :)
Здравствуйте, Pavel Dvorkin, Вы писали:

E>>Смотри, стека в типичном приложении обычно резервируют метр. При этом ещё надо, чтобы он весь отмотался при работе приложения. Так что обычно стек и того меньше. Кучи в каком-нибудь нетяжёлом приложении обычно десятки метров максимум. Доступных по записи статических данных -- вообще мизер. Десятки килобайт возможно будет.


PD>М-да...


PD>int a[1000000];

PD>void main()
PD>{
PD>}

Это, по твоему, типичное приложение, да?

E>>Обычно куча расстреливается совсем не так. Намного более реалистичный сценарий -- запись либо в освобождённый блок, либо недалеко от границы аллокированного.

PD>С этим я согласен.

Тогда я не понимаю, чего ты не понимаешь...
PD>Неужели ? ИМХО для этого достаточно сохранить указатель на локальную переменную и потом когда-нибудь им воспользоваться, когда стек будет, к несчастью, больше Не пробовал ?

1) Не пробовал. Я вообще стараюсь писать качественный код.
2) Для этого надо не просто дождаться момента, когда стек станет больше, но ещё и выйти сначала из той функции, на фрейме которой была создана та самая переменная. Это довольно хитрое стечение обстоятельств.

PD>Прелесть! Я эту фразу студентам повторять буду. Надо же иногда разрядку делать .

Я рад, что тебе весело, но попробуй понять, что тебе пишут.

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


Для "спасибо" тут есть кнопки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: выделение памяти
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 18:19
Оценка: +1
Здравствуйте, Кодт, Вы писали:

ТКС>>Мы вообще-то уже про порчу стека терли А с хипом самое полезное средство из MS'овских — отладочный флаг, запрещающий возврат освобожденного блока в хип. В многопоточных программах с фоновой активностью помогает радикально.


К>И что при этом происходит? Выжирание памяти?


Если проблема заключалась в записи в уже освобожденный блок, то исключается ситуация, когда из-за этого упадет совершенно другая подсистема. Программа доживет до вызова _CrtCheckMemory, при котором будет найден проблемный блок. В общем, стабильность воспроизведения ошибки увеличится во много раз.
Если проблема заключалась в записи вообще куда попало, то, очевидно, такой фокус не поможет.

К>Опять же, есть такая проблема "ABA" — когда из равенства адресов (текущего и запомненного) делают вывод о неизменности содержимого.

К>Она актуальна для лок-фри алгоритмов, но, мало ли где есть говнокод на основе этого антипаттерна...
К>С хипом это выглядит так: создали блок, запомнили, попользовались, удалили, создали новый, опа.

Тут я первым делом вспоминаю трекинг объектов в boost::serialization
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[10]: выделение памяти
От: McSeem2 США http://www.antigrain.com
Дата: 20.08.10 18:44
Оценка: -1
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Если проблема заключалась в записи в уже освобожденный блок, то исключается ситуация, когда из-за этого упадет совершенно другая подсистема. Программа доживет до вызова _CrtCheckMemory, при котором будет найден проблемный блок. В общем, стабильность воспроизведения ошибки увеличится во много раз.


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

А запрет на возврат памяти — это значит доблестно притвориться, что проблемы не существует. "Давайте задернем занавески и будем думать, что мы едем".
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[11]: выделение памяти
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 19:58
Оценка: +1
Здравствуйте, McSeem2, Вы писали:

ТКС>>Если проблема заключалась в записи в уже освобожденный блок, то исключается ситуация, когда из-за этого упадет совершенно другая подсистема. Программа доживет до вызова _CrtCheckMemory, при котором будет найден проблемный блок. В общем, стабильность воспроизведения ошибки увеличится во много раз.


MS>По-моему, как раз все наоборот. Если освобожденные блоки всегда размапировать физически, то падать будет именно в том месте, где происходит обращение и виновник мгновенно обнаруживается.


Это во-первых менеджер хипа свой ставить надо, что не всегда реально, во-вторых по странице на блок придется тратить, что еще менее реально.

MS>А запрет на возврат памяти — это значит доблестно притвориться, что проблемы не существует. "Давайте задернем занавески и будем думать, что мы едем".


Ну хоть чуть-чуть надо стараться понять, на что отвечаешь, перед тем как пишешь, а? Я вроде понятно написал — делается это для того, чтобы программа успела доработать до ближайшего вызова _CrtCheckMemory, который найдет битый блок и напишет об этом в debug output. Дальше по адресу и номеру блока можно разбираться дальше.
Была реальная ситуация — после некоторого действия в GUI из обработчика какого-то оконного события шла запись в только что удаленный узел tree control'а. Обычно это попадало в блок, используемый нитью, опрашивающей сервер (так совпадало — размер блока видимо как раз подходил) — и все падало не дожив до следующей аллокации, причем в другой подсистеме. После установки флага _CRTDBG_DELAY_FREE_MEM_DF все встало на свои места, падать начало вообще детерминированно. После пристального разглядывания вершины стека стало понятно, что память портится во время удаления узла дерева, даже сторонние инструментальные средства не понадобились.
А ты — "занавески задернем"
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
выделение памяти
От: Аноним  
Дата: 19.08.10 11:52
Оценка:
подскажите, почему, иногда вываливается ошибка при выделениии памяти:

unsigned __int64 *bud_cnl;


typedef struct
{
...
 unsigned __int64 *bud_cnl;
...
} TSt;
TSt *st;
st = new TSt[2000];


st[i1].bud_cnl   = new unsigned __int64[13]; // Здесь ошибка!!!



систематику ошибки не понимаю(((
еще вопрос какой самый большой целочисленный беззнаковый тип в builder6?
Re: выделение памяти
От: Кодт Россия  
Дата: 19.08.10 12:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>подскажите, почему, иногда вываливается ошибка при выделениии памяти:

А>unsigned __int64 *bud_cnl;


А>typedef struct
А>{
А>...
А> unsigned __int64 *bud_cnl;
А>...
А>} TSt;
А>TSt *st;
А>st = new TSt[2000];


А>st[i1].bud_cnl   = new unsigned __int64[13]; // Здесь ошибка!!!

А какая именно ошибка вываливается?

Причины:
— реально исчерпана память, — вылетает std::bad_alloc
— опять же, исчерпана память, но это хэндлится где-то в недрах рантайма, и вылетает что-нибудь родное, билдеровское
— индекс i1 выехал за пределы [0..2000), пытаемся записать указатель куда-то нафиг
— st повреждён или обнулён, — такой же эффект
— когда-то раньше была расстреляна куча, — new не смог нормально отработать
Перекуём баги на фичи!
Re[2]: выделение памяти
От: piero_  
Дата: 19.08.10 12:31
Оценка:
К>А какая именно ошибка вываливается?

К>Причины:

К>- реально исчерпана память, — вылетает std::bad_alloc
К>- опять же, исчерпана память, но это хэндлится где-то в недрах рантайма, и вылетает что-нибудь родное, билдеровское
К>- индекс i1 выехал за пределы [0..2000), пытаемся записать указатель куда-то нафиг
К>- st повреждён или обнулён, — такой же эффект
К>- когда-то раньше была расстреляна куча, — new не смог нормально отработать

access vialation
нет все впрорядке, что значит кучу растерять? может как-то подругому выделять память?
Re[4]: выделение памяти
От: Pavel Dvorkin Россия  
Дата: 19.08.10 13:53
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.


Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.
И про расстрел статических данных я тоже что-то не помню.
With best regards
Pavel Dvorkin
Re[5]: выделение памяти
От: Тот кто сидит в пруду Россия  
Дата: 19.08.10 15:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

К>>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.


PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.

PD>И про расстрел статических данных я тоже что-то не помню.

Я однажды по молодости такую херь чуть ли не неделю ловил...
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[5]: про расстрелы разных storages
От: Erop Россия  
Дата: 19.08.10 19:27
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>И про расстрел статических данных я тоже что-то не помню.


Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.
Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.

Кроме того, многие менеджеры кучи могут распространять внутри себя ошибку. То есть раз испортишь ему структуру данных и привет, он постепенно всё пережуёт в какую-то рвань.
Ну и ещё надо понимать, что стек относительно небольшой, кстати. Но в большинстве программ и куча небольшая, по сравнению с адресным пространством.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: выделение памяти
От: McSeem2 США http://www.antigrain.com
Дата: 20.08.10 00:16
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Я однажды по молодости такую херь чуть ли не неделю ловил...


Для этого существуют отладочные средства. Например, я специально сделал такое против пропарывания памяти. Идея простая — на каждый alloc аллокируется как минимум одна физическая страница в 4K и аллокация размещается в самом конце блока. А после блока должна быть незамапированная страница, обращение к которой мгновенно вызывает падение. Поскольку Интел вполне может работать с невыровненными данными (хоть и тормозно), такой фокус прокатывает. Да, по отжиранию памяти и тормозам — жесткая жесть, но зато виновник определяется мгновенно, в отличие от репортов Микрософтовского аллокатора. Заодно, с очень хорошей вероятностью, ловится обращение к освобожденной памяти даже на чтение — вот это то, что никакой аллокатор не способен отловить. Чтобы повысить вероятность успешного отлова, все доступное адресное пространство работает в закольцованном режиме. Фрагментация, тормоза, отжирание памяти дикие, да. Но зато проблема находится очень быстро.

Да, на всякий случай, чтобы не было кривотолоков. Сам-то я такой фигней типа порчи памяти уже лет 15 как не страдаю. Но вот у "братьев наших меньших" такое происходит регулярно. А самый прикол — мы используем мой супер-аллокатор, из за которого я в некоторой степени пострадал. Потому что мой аллокатор не держит никаких заголовков перед блоками. А если затереть хоть один лишний байт, то затирается либо следующщая аллокация, либо служебные структуры в свободных блоках. В результате, поступают жалобы — типа "твой аллокатор падает". И не скрою, мне временами бывает прикольно ткнуть этих товарищей носом в ихнюю лажу. Работаю ассенизатором, в общем.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[7]: про расстрелы разных storages
От: Erop Россия  
Дата: 20.08.10 09:01
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Возможный расстрел стека я описал подробно. Расстрел статических данных — коротко, в надежде, что читающий поймет, что порча статических данных входит под понятие "расстрел" как я его тут употребляю.


Это довольно маловероятный сценарий.

PD>Для этого совсем не требуется освобождать их — вполне достаточно записать по левому указатель. Если он случайно показывает внутрь стека — будет расстрел стека, если внутрь статических данных — ни с того ни с сего изменится значение некоей глобальной или статической в функции переменной.


Смотри, стека в типичном приложении обычно резервируют метр. При этом ещё надо, чтобы он весь отмотался при работе приложения. Так что обычно стек и того меньше. Кучи в каком-нибудь нетяжёлом приложении обычно десятки метров максимум. Доступных по записи статических данных -- вообще мизер. Десятки килобайт возможно будет. А адресного пространства на 32-битной ОС целых 4 гига. Так что если мы возьмём *случайный* адрес в памяти, то скорее всего попадём на AV. При этом, попасть в стек есть что-то около одного шанса на несколько тысяч, в кучу -- на несколько тысяч, а в статические данные вообще шансы мизерные.
Обычно куча расстреливается совсем не так. Намного более реалистичный сценарий -- запись либо в освобождённый блок, либо недалеко от границы аллокированного.
В отличии от кучи, запись в стек по устаревшему адресу довольно трудно организовать НЕПРЕДНАМЕРЕННО, а в статические данные вообще невозможно.
Если же мы пишем рядом с нужным адресом, то в стеке последствия происходят тоже где-то "рядом", например мы не можем вернуться из ошибочной функции. А вот в куче совсем другая история. Запись рядом с выделенным блоком может сказаться сколь угодно отложено и сколь угодно замысловато.

PD>Кстати, стек совсем не так просто устроен, как тебе кажется, и его storage (в смысле коммитированной памяти в Windows) тоже никогда не освобождается, когда стек уменьшается. Другое дело, что эта память, хоть и остается коммитированной, не принадлежит собственно стеку (принадлежит только региону стека потока)


Эх, дядя. Тебе бы послушать, что практики говорят. Ты-то не понимаешь, почему кучу расстреливают намного чаще, чем стек, а я вот понимаю
E>>Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.

PD>И что же в итоге ? Стек небольшой, куча небольшая, стек расстреливают редко, кучу часто.

В том, что обычно кучу расстреливают не так, как ты себе это представляешь

PD>В чем тут аргументы — пойди пойми.

То, что ты не можешь понять аргументы, говорит, IMHO, о том, что я недостаточно понятно объясняю, а до тебя недостаточно легко доходит.
Но теперь я вот тебе разжевал всё, с прикидками вероятностей тех или иных сценариев, даже. При этом прикидки ещё завышают вероятность расстрела стека. Так как, на самом деле, "случайный адрес" часто не совсем случайный, а какое-то число. А *какое-то число* часто бывает небольшим, что повышает вероятность AV...

Вообще-то это хамство. Ты задал вопрос, я дал тебе на него ответ. Ответ всего из трёх строк:

Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.
Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.

Но ты, вместо того, чтобы переспросить то, что тебе трудно в этих трёх строчках понять, или обсудить то, что кажется тебе спорным, начинаешь ставить двойки. При этом сам ответа на свой вопрос даже не представляешь. Так дискуссию приличные люди не ведут. Если тебе кажется, что я заблуждаюсь -- аргументированно развей сомнения. Если заблуждаешься ты, то поблагодари за науку. А говорить собеседнику, в ответ на желание помочь тебе решить твои проблемы, что собеседник дурак -- это обычное бытовое хамство. Фи, товарищ препод!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
й
Re[5]: выделение памяти
От: Sergey Chadov Россия  
Дата: 20.08.10 09:16
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


К>>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.


PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.

PD>И про расстрел статических данных я тоже что-то не помню.

Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций
Re[8]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 09:23
Оценка:
Здравствуйте, Erop, Вы писали:


PD>>Возможный расстрел стека я описал подробно. Расстрел статических данных — коротко, в надежде, что читающий поймет, что порча статических данных входит под понятие "расстрел" как я его тут употребляю.


E>Это довольно маловероятный сценарий.


Почему ? Менее вероятен, чем расстрел кучи, согласен. Но почему он менее вероятен, чем расстрел стека ?

PD>>Для этого совсем не требуется освобождать их — вполне достаточно записать по левому указатель. Если он случайно показывает внутрь стека — будет расстрел стека, если внутрь статических данных — ни с того ни с сего изменится значение некоей глобальной или статической в функции переменной.


E>Смотри, стека в типичном приложении обычно резервируют метр. При этом ещё надо, чтобы он весь отмотался при работе приложения. Так что обычно стек и того меньше. Кучи в каком-нибудь нетяжёлом приложении обычно десятки метров максимум. Доступных по записи статических данных -- вообще мизер. Десятки килобайт возможно будет.


М-да...

int a[1000000];
void main()
{
}


E>Обычно куча расстреливается совсем не так. Намного более реалистичный сценарий -- запись либо в освобождённый блок, либо недалеко от границы аллокированного.


С этим я согласен.

E>В отличии от кучи, запись в стек по устаревшему адресу довольно трудно организовать НЕПРЕДНАМЕРЕННО


Неужели ? ИМХО для этого достаточно сохранить указатель на локальную переменную и потом когда-нибудь им воспользоваться, когда стек будет, к несчастью, больше Не пробовал ?


E>Если же мы пишем рядом с нужным адресом, то в стеке последствия происходят тоже где-то "рядом", например мы не можем вернуться из ошибочной функции. А вот в куче совсем другая история. Запись рядом с выделенным блоком может сказаться сколь угодно отложено и сколь угодно замысловато.


PD>>Кстати, стек совсем не так просто устроен, как тебе кажется, и его storage (в смысле коммитированной памяти в Windows) тоже никогда не освобождается, когда стек уменьшается. Другое дело, что эта память, хоть и остается коммитированной, не принадлежит собственно стеку (принадлежит только региону стека потока)


E>Эх, дядя. Тебе бы послушать, что практики говорят. Ты-то не понимаешь, почему кучу расстреливают намного чаще, чем стек, а я вот понимаю


Ох

E>То, что ты не можешь понять аргументы, говорит, IMHO, о том, что я недостаточно понятно объясняю, а до тебя недостаточно легко доходит.

E>Но теперь я вот тебе разжевал всё, с прикидками вероятностей тех или иных сценариев, даже.

Да уж, с таким входными данными и с таким пониманием , как все работает, можно все, что угодно, оценить как угодно.

>При этом прикидки ещё завышают вероятность расстрела стека. Так как, на самом деле, "случайный адрес" часто не совсем случайный, а какое-то число.




Прелесть! Я эту фразу студентам повторять буду. Надо же иногда разрядку делать .


E>
Вообще-то это хамство. Ты задал вопрос, я дал тебе на него ответ.

Ответ всего из трёх строк:

Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.
E>Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
E>Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.

E>Но ты, вместо того, чтобы переспросить то, что тебе трудно в этих трёх строчках понять, или обсудить то, что кажется тебе спорным, начинаешь ставить двойки. При этом сам ответа на свой вопрос даже не представляешь.

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


>Так дискуссию приличные люди не ведут. Если тебе кажется, что я заблуждаюсь -- аргументированно развей сомнения.


Ну уж нет, с меня хватит. Аргументированно что-то делать в дискуссии с тобой — пустая трата времени и сил.

>Если заблуждаешься ты, то поблагодари за науку.


Я действительно заблуждался, принимая тебя до этого за человека, с которым можно о чем-то дискутировать. Благодарю за науку, что избавил меня от этого заблуждения.
With best regards
Pavel Dvorkin
Re[8]: про расстрелы разных storages
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 09:27
Оценка:
Здравствуйте, Erop, Вы писали:

E>В отличии от кучи, запись в стек по устаревшему адресу довольно трудно организовать НЕПРЕДНАМЕРЕННО, а в статические данные вообще невозможно.


Вообще-то на раз:

string& foo()
{
  int a[20];
  string x;
}

void bar(string &x)
{
  x.resize(10);
}

void ignite()
{
  string &q = foo();
  {
    myClass m[10];
    bar(q);
  }
}


Другое дело, что нынешний VC такие гадости четко отлавливает. Ну а соответствующий ворнинг лично я всегда назначаю ошибкой.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[10]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 09:50
Оценка:
Здравствуйте, Erop, Вы писали:

PD>>М-да...


PD>>int a[1000000];

PD>>void main()
PD>>{
PD>>}

E>Это, по твоему, типичное приложение, да?


Ох! Сил уже нет.

E>Тогда я не понимаю, чего ты не понимаешь...


Я все вполне понимаю, но сил с тобой дискутировать больше нет.

PD>>Неужели ? ИМХО для этого достаточно сохранить указатель на локальную переменную и потом когда-нибудь им воспользоваться, когда стек будет, к несчастью, больше Не пробовал ?


E>1) Не пробовал. Я вообще стараюсь писать качественный код.




E>2) Для этого надо не просто дождаться момента, когда стек станет больше, но ещё и выйти сначала из той функции, на фрейме которой была создана та самая переменная. Это довольно хитрое стечение обстоятельств.


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

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


E>Для "спасибо" тут есть кнопки


Увы, нет кнопки "Господи, помилуй". Минусы я ставить не очень люблю, а смайлики ставлю в основном по прямому назначению — когда мне действительно смешно. А тут плакать хочется
With best regards
Pavel Dvorkin
Re[9]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 10:00
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:




ТКС>Вообще-то на раз:


Можно и проще

int* f()
{
    int a[100];
    int* t = a + 50;
    return t;
}

void g(int* p)
{
    int a[100];
    for (int i = 0; i < 100; i++)
        a[i] = i;
    *p = 666;
// это что же такое с a[51] случилось ??? 
}

int _tmain(int argc, _TCHAR* argv[])
{
    int* p = f();
    g(p);
    return 0;
}


И предупреждений нет, даже при Level4.
With best regards
Pavel Dvorkin
Re[8]: про расстрелы разных storages
От: Rothmans  
Дата: 20.08.10 10:28
Оценка:
Здравствуйте, Erop, Вы писали:

E> А говорить собеседнику, в ответ на желание помочь тебе решить твои проблемы, что собеседник дурак -- это обычное бытовое хамство.


Это не то чтобы хамство, это вы добровольно попали в треугольник Карпмана.
Re[9]: про расстрелы разных storages
От: Erop Россия  
Дата: 20.08.10 10:35
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Другое дело, что нынешний VC такие гадости четко отлавливает. Ну а соответствующий ворнинг лично я всегда назначаю ошибкой.


Ну так в том-то и фишка, что такие ошибки долго не живут и проблем никому не доставляют. ОБЫЧНО, так скажем.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: про расстрелы разных storages
От: Erop Россия  
Дата: 20.08.10 10:42
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Правильно мыслишь. Добавлю — не только выйти оттуда, но и зайти еще куда-то. Это само по себе отнюдь не хитрое стечение обстоятельств, и уж во всяком случае не более хитрое, чем запись по освобожденному указателю в куче. Строго говоря, это вообще практически эквивалентные ситуации. В обоих случаях речь идет о попытке записи туда, где раньше было то, что надо , но теперь уже нечто иное.


Ну так такие ошибки обычно легко обнаруживаются. Трудность обнаружения расстрела кучи именно в том и состоит, то наблюдаемые последствия очень сильно отдалены от самого акта расстрела. Со стеком так ОБЫЧНО не бывает.

PD>Увы, нет кнопки "Господи, помилуй". Минусы я ставить не очень люблю, а смайлики ставлю в основном по прямому назначению — когда мне действительно смешно. А тут плакать хочется

"минус" -- это " не согласен"...

В общем я думаю, что ответ на вопрос "почему расстреливают обычно кучи, а не остальные структуры данных в памяти?" мы совместными усилиями нашли. На том предлагаю и завязать, если у тебя нет добавить ещё чего-то по существу вопроса
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: про расстрелы разных storages
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 10:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Можно и проще


PD>
PD>int* f()
PD>{
PD>    int a[100];
PD>    int* t = a + 50;
PD>    return t;
PD>}

PD>void g(int* p)
PD>{
PD>    int a[100];
PD>    for (int i = 0; i < 100; i++)
PD>        a[i] = i;
PD>    *p = 666;
PD>// это что же такое с a[51] случилось ??? 
PD>}

PD>int _tmain(int argc, _TCHAR* argv[])
PD>{
PD>    int* p = f();
PD>    g(p);
PD>    return 0;
PD>}

PD>


PD>И предупреждений нет, даже при Level4.


Вероятность написать такое случайно на порядки ниже, чем, например, вероятность пропустить амперсенд в цепочке функций, возвращающих ссылку на объект. По крайней мере, для вменяемого разработчика.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[11]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 11:01
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Вероятность написать такое случайно на порядки ниже, чем, например, вероятность пропустить амперсенд в цепочке функций, возвращающих ссылку на объект. По крайней мере, для вменяемого разработчика.


Да не случайно я это написал, не случайно. Просто раньше массив int a[100] из функции f был глобальным. Глобальные данные — это не хорошо . Показалось, что он вроде как и не нужен за пределами f, ну вот его туда и перенес

P.S. "Я" тут иносказательно. А то прочтет Егор и устроит новые поучения
With best regards
Pavel Dvorkin
Re[12]: про расстрелы разных storages
От: Тот кто сидит в пруду Россия  
Дата: 20.08.10 11:18
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

ТКС>>Вероятность написать такое случайно на порядки ниже, чем, например, вероятность пропустить амперсенд в цепочке функций, возвращающих ссылку на объект. По крайней мере, для вменяемого разработчика.


PD>Да не случайно я это написал, не случайно. Просто раньше массив int a[100] из функции f был глобальным. Глобальные данные — это не хорошо . Показалось, что он вроде как и не нужен за пределами f, ну вот его туда и перенес


Ну про вменяемого разработчика я тоже не случайно написал
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[13]: про расстрелы разных storages
От: Pavel Dvorkin Россия  
Дата: 20.08.10 11:21
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

PD>>Да не случайно я это написал, не случайно. Просто раньше массив int a[100] из функции f был глобальным. Глобальные данные — это не хорошо . Показалось, что он вроде как и не нужен за пределами f, ну вот его туда и перенес


ТКС>Ну про вменяемого разработчика я тоже не случайно написал


Конечно, это уже доведено до абсурда. Но в более сложном виде вполне возможно, даже при вменяемом разработчике.
With best regards
Pavel Dvorkin
Re[8]: выделение памяти
От: Кодт Россия  
Дата: 20.08.10 14:41
Оценка:
Здравствуйте, Тот кто сидит в пруду, Вы писали:

ТКС>Мы вообще-то уже про порчу стека терли А с хипом самое полезное средство из MS'овских — отладочный флаг, запрещающий возврат освобожденного блока в хип. В многопоточных программах с фоновой активностью помогает радикально.


И что при этом происходит? Выжирание памяти?

Опять же, есть такая проблема "ABA" — когда из равенства адресов (текущего и запомненного) делают вывод о неизменности содержимого.
Она актуальна для лок-фри алгоритмов, но, мало ли где есть говнокод на основе этого антипаттерна...
С хипом это выглядит так: создали блок, запомнили, попользовались, удалили, создали новый, опа.
Перекуём баги на фичи!
Re[5]: выделение памяти
От: Кодт Россия  
Дата: 20.08.10 14:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.

PD>И про расстрел статических данных я тоже что-то не помню.

Потому что диагностировать запиленный стек несложно: увидим мусор прямо в отладчике.
А вот запиленная куча — это очень отдалённые и очень неявные последствия.

Хорошо, если мы повредили собственные данные. Увидим в них мусор и поймём, что случилась беда.
А если мы повредили список блоков в менеджере кучи (достаточно стрельнуть по отрицательному смещению от выделенного блока) — то в какой-то момент менеджер или решит, что память исчерпана, или повторно выделит уже занятый блок, или просто рухнет.
Перекуём баги на фичи!
Re[2]: выделение памяти
От: Vamp Россия  
Дата: 20.08.10 16:20
Оценка:
К>Топикстартер, наверно, обалдевает — как такой простой и невинный вопрос спровоцировал старожилов на флейм с мордобоем
Стек, куча... Я вот никогда не забуду, как у меня приложение корилось из-за тернарного оператора!
Да здравствует мыло душистое и веревка пушистая.
Re[6]: выделение памяти
От: Pavel Dvorkin Россия  
Дата: 21.08.10 09:09
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Потому что диагностировать запиленный стек несложно: увидим мусор прямо в отладчике.


А как отличить мусор от немусора в глубине стека ?

К>А вот запиленная куча — это очень отдалённые и очень неявные последствия.


И в стеке могут быть тоже отдаленные.

К>Хорошо, если мы повредили собственные данные. Увидим в них мусор и поймём, что случилась беда.


И в стеке — тоже, если это числа. А если указатели ? адреса возврата ?

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


+1
With best regards
Pavel Dvorkin
Re[7]: выделение памяти
От: Кодт Россия  
Дата: 21.08.10 09:20
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

К>>Потому что диагностировать запиленный стек несложно: увидим мусор прямо в отладчике.

PD>А как отличить мусор от немусора в глубине стека ?

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

Не значит, что мы гарантированно распознаем, что стек запилен — но шансы есть.
Опять же, компиляторы умеют подвёрстывать проверки (ну, хотя бы согласованность значений ESP и EBP).
Перекуём баги на фичи!
Re[8]: выделение памяти
От: Pavel Dvorkin Россия  
Дата: 21.08.10 09:48
Оценка:
Здравствуйте, Кодт, Вы писали:

PD>>А как отличить мусор от немусора в глубине стека ?


К>Внезапные значения переменных, посторонние или уничтоженные точки вызова.

К>Увидел, что какая-то фигня началась, остановился, пробежал глазами... этто что ещё за штуки?!

Во-первых, это надо еще догадаться. что именно стек испорчен, а не что-то иное.
Во-вторых, как его просматривать ? Возле ESP — понятно, а на глубину, скажем, 30-40 Кб ? Будем в окошке Memory тупо листать страницы и пялить глаза в байты ?
В третьих, все же неясно, как фигню отличить от нефигни. Например, увижу я там что-то вроде 0xcdcdcdcd. Это фигня ? Да нет, совсем необязательно, просто неинициализированный пока что элемент автоматического массива. А 0x7e2345FCA — это фигня или нормальный адрес в области системных DLL ?

К>Не значит, что мы гарантированно распознаем, что стек запилен — но шансы есть.

К>Опять же, компиляторы умеют подвёрстывать проверки (ну, хотя бы согласованность значений ESP и EBP).

Я же говорю — возле ESP это обычно не проблема, хуже, когда в глубине.
With best regards
Pavel Dvorkin
Re[8]: выделение памяти
От: Erop Россия  
Дата: 23.08.10 02:29
Оценка:
Здравствуйте, Sergey Chadov, Вы писали:

SC>>>Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций

E>>А хрен ли она не read-only? Типа из-за настройки адресов при загрузке?

SC>А хрен-ли ей быть рид-онли?



SC>
SC>struct A{
SC>    virtual void M1(){
SC>        printf("M1\n");
SC>    }
SC>    virtual void M2(){
SC>        printf("M2\n");
SC>    }
SC>};

SC>int main(int argc, char* argv[])
SC>{
SC>    A* a = new A;
    a->>M1();
SC>    *((int*)a)+=4;
    a->>M1();
SC>    return 0;
SC>}
SC>

Это просто расстрел данных. В данном случае портится указатель на таблицу виртуальных функций, а не сама таблица...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: выделение памяти
От: Erop Россия  
Дата: 23.08.10 02:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Во-вторых, как его просматривать ? Возле ESP — понятно, а на глубину, скажем, 30-40 Кб ? Будем в окошке Memory тупо листать страницы и пялить глаза в байты ?

Многие отладчики умеют показывать стек в читаемой форме

PD>Например, увижу я там что-то вроде 0xcdcdcdcd. Это фигня ? Да нет, совсем необязательно, просто неинициализированный пока что элемент автоматического массива.


Это, кстати, совсем нехарактерное значение для неинициализированной автоматической переменной...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: выделение памяти
От: carpenter СССР  
Дата: 24.08.10 21:26
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


К>>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.


PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ?


в 7ке багу отловил — расстреливало стек при при отрисовке линий определенным типом карандаша
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.