Здравствуйте, Аноним, Вы писали:
А>подскажите, почему, иногда вываливается ошибка при выделениии памяти:
А>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 не смог нормально отработать
К>А какая именно ошибка вываливается?
К>Причины: К>- реально исчерпана память, — вылетает std::bad_alloc К>- опять же, исчерпана память, но это хэндлится где-то в недрах рантайма, и вылетает что-нибудь родное, билдеровское К>- индекс i1 выехал за пределы [0..2000), пытаемся записать указатель куда-то нафиг К>- st повреждён или обнулён, — такой же эффект К>- когда-то раньше была расстреляна куча, — new не смог нормально отработать
access vialation
нет все впрорядке, что значит кучу растерять? может как-то подругому выделять память?
Здравствуйте, piero_, Вы писали:
_>access vialation _>нет все впрорядке, что значит кучу растерять? может как-то подругому выделять память?
Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.
После этого ни new[], ни malloc() работать по-нормальному уже не смогут, и будут непредсказуемо глючить.
Если в данном месте все переменные выглядят нормально, а new[], тем не менее, говорит AV — то 99%, что это плоды давнишнего расстрела.
Здравствуйте, Кодт, Вы писали:
К>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.
Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.
И про расстрел статических данных я тоже что-то не помню.
PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.
А я помню такой случай. Но не надо о грустном.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, Pavel Dvorkin, Вы писали:
К>>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.
PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные. PD>И про расстрел статических данных я тоже что-то не помню.
Я однажды по молодости такую херь чуть ли не неделю ловил...
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>И про расстрел статических данных я тоже что-то не помню.
Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.
Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.
Кроме того, многие менеджеры кучи могут распространять внутри себя ошибку. То есть раз испортишь ему структуру данных и привет, он постепенно всё пережуёт в какую-то рвань.
Ну и ещё надо понимать, что стек относительно небольшой, кстати. Но в большинстве программ и куча небольшая, по сравнению с адресным пространством.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Тот кто сидит в пруду, Вы писали:
ТКС>Я однажды по молодости такую херь чуть ли не неделю ловил...
Для этого существуют отладочные средства. Например, я специально сделал такое против пропарывания памяти. Идея простая — на каждый alloc аллокируется как минимум одна физическая страница в 4K и аллокация размещается в самом конце блока. А после блока должна быть незамапированная страница, обращение к которой мгновенно вызывает падение. Поскольку Интел вполне может работать с невыровненными данными (хоть и тормозно), такой фокус прокатывает. Да, по отжиранию памяти и тормозам — жесткая жесть, но зато виновник определяется мгновенно, в отличие от репортов Микрософтовского аллокатора. Заодно, с очень хорошей вероятностью, ловится обращение к освобожденной памяти даже на чтение — вот это то, что никакой аллокатор не способен отловить. Чтобы повысить вероятность успешного отлова, все доступное адресное пространство работает в закольцованном режиме. Фрагментация, тормоза, отжирание памяти дикие, да. Но зато проблема находится очень быстро.
Да, на всякий случай, чтобы не было кривотолоков. Сам-то я такой фигней типа порчи памяти уже лет 15 как не страдаю. Но вот у "братьев наших меньших" такое происходит регулярно. А самый прикол — мы используем мой супер-аллокатор, из за которого я в некоторой степени пострадал. Потому что мой аллокатор не держит никаких заголовков перед блоками. А если затереть хоть один лишний байт, то затирается либо следующщая аллокация, либо служебные структуры в свободных блоках. В результате, поступают жалобы — типа "твой аллокатор падает". И не скрою, мне временами бывает прикольно ткнуть этих товарищей носом в ихнюю лажу. Работаю ассенизатором, в общем.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
ТКС>>Я однажды по молодости такую херь чуть ли не неделю ловил...
MS>Для этого существуют отладочные средства. Например, я специально сделал такое против пропарывания памяти. Идея простая — на каждый alloc аллокируется как минимум одна физическая страница в 4K и аллокация размещается в самом конце блока. А после блока должна быть незамапированная страница, обращение к которой мгновенно вызывает падение. Поскольку Интел вполне может работать с невыровненными данными (хоть и тормозно), такой фокус прокатывает. Да, по отжиранию памяти и тормозам — жесткая жесть, но зато виновник определяется мгновенно, в отличие от репортов Микрософтовского аллокатора. Заодно, с очень хорошей вероятностью, ловится обращение к освобожденной памяти даже на чтение — вот это то, что никакой аллокатор не способен отловить. Чтобы повысить вероятность успешного отлова, все доступное адресное пространство работает в закольцованном режиме. Фрагментация, тормоза, отжирание памяти дикие, да. Но зато проблема находится очень быстро.
Мы вообще-то уже про порчу стека терли А с хипом самое полезное средство из MS'овских — отладочный флаг, запрещающий возврат освобожденного блока в хип. В многопоточных программах с фоновой активностью помогает радикально.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Erop, Вы писали:
E>Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем. E>Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
Уф... Ты то и дело совершаешь открытия, за которые я двойку бы поставил студентам, если бы вообще ставил какие-то оценки.
Цитирую себя. И выделяю.
PD>То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные.И про расстрел статических данных я тоже что-то не помню.
Возможный расстрел стека я описал подробно. Расстрел статических данных — коротко, в надежде, что читающий поймет, что порча статических данных входит под понятие "расстрел" как я его тут употребляю.
Для этого совсем не требуется освобождать их — вполне достаточно записать по левому указатель. Если он случайно показывает внутрь стека — будет расстрел стека, если внутрь статических данных — ни с того ни с сего изменится значение некоей глобальной или статической в функции переменной.
Кстати, стек совсем не так просто устроен, как тебе кажется, и его storage (в смысле коммитированной памяти в Windows) тоже никогда не освобождается, когда стек уменьшается. Другое дело, что эта память, хоть и остается коммитированной, не принадлежит собственно стеку (принадлежит только региону стека потока)
E>Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.
E>Ну и ещё надо понимать, что стек относительно небольшой, кстати. Но в большинстве программ и куча небольшая, по сравнению с адресным пространством.
И что же в итоге ? Стек небольшой, куча небольшая, стек расстреливают редко, кучу часто. В чем тут аргументы — пойди пойми.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Возможный расстрел стека я описал подробно. Расстрел статических данных — коротко, в надежде, что читающий поймет, что порча статических данных входит под понятие "расстрел" как я его тут употребляю.
Это довольно маловероятный сценарий.
PD>Для этого совсем не требуется освобождать их — вполне достаточно записать по левому указатель. Если он случайно показывает внутрь стека — будет расстрел стека, если внутрь статических данных — ни с того ни с сего изменится значение некоей глобальной или статической в функции переменной.
Смотри, стека в типичном приложении обычно резервируют метр. При этом ещё надо, чтобы он весь отмотался при работе приложения. Так что обычно стек и того меньше. Кучи в каком-нибудь нетяжёлом приложении обычно десятки метров максимум. Доступных по записи статических данных -- вообще мизер. Десятки килобайт возможно будет. А адресного пространства на 32-битной ОС целых 4 гига. Так что если мы возьмём *случайный* адрес в памяти, то скорее всего попадём на AV. При этом, попасть в стек есть что-то около одного шанса на несколько тысяч, в кучу -- на несколько тысяч, а в статические данные вообще шансы мизерные.
Обычно куча расстреливается совсем не так. Намного более реалистичный сценарий -- запись либо в освобождённый блок, либо недалеко от границы аллокированного.
В отличии от кучи, запись в стек по устаревшему адресу довольно трудно организовать НЕПРЕДНАМЕРЕННО, а в статические данные вообще невозможно.
Если же мы пишем рядом с нужным адресом, то в стеке последствия происходят тоже где-то "рядом", например мы не можем вернуться из ошибочной функции. А вот в куче совсем другая история. Запись рядом с выделенным блоком может сказаться сколь угодно отложено и сколь угодно замысловато.
PD>Кстати, стек совсем не так просто устроен, как тебе кажется, и его storage (в смысле коммитированной памяти в Windows) тоже никогда не освобождается, когда стек уменьшается. Другое дело, что эта память, хоть и остается коммитированной, не принадлежит собственно стеку (принадлежит только региону стека потока)
Эх, дядя. Тебе бы послушать, что практики говорят. Ты-то не понимаешь, почему кучу расстреливают намного чаще, чем стек, а я вот понимаю E>>Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.
PD>И что же в итоге ? Стек небольшой, куча небольшая, стек расстреливают редко, кучу часто.
В том, что обычно кучу расстреливают не так, как ты себе это представляешь
PD>В чем тут аргументы — пойди пойми.
То, что ты не можешь понять аргументы, говорит, IMHO, о том, что я недостаточно понятно объясняю, а до тебя недостаточно легко доходит.
Но теперь я вот тебе разжевал всё, с прикидками вероятностей тех или иных сценариев, даже. При этом прикидки ещё завышают вероятность расстрела стека. Так как, на самом деле, "случайный адрес" часто не совсем случайный, а какое-то число. А *какое-то число* часто бывает небольшим, что повышает вероятность AV... Вообще-то это хамство. Ты задал вопрос, я дал тебе на него ответ. Ответ всего из трёх строк:
Потому, что в куче это сделать намного проще. Достаточно поработать с уже освобождённым указателем.
Со стеком это намного сложнее устроить, а со статическими данными совсем нельзя. Их storage не освобождается вовсе
Ну а если мы возьмём случайный адрес, то, в большинстве программ получим просто AV.
Но ты, вместо того, чтобы переспросить то, что тебе трудно в этих трёх строчках понять, или обсудить то, что кажется тебе спорным, начинаешь ставить двойки. При этом сам ответа на свой вопрос даже не представляешь. Так дискуссию приличные люди не ведут. Если тебе кажется, что я заблуждаюсь -- аргументированно развей сомнения. Если заблуждаешься ты, то поблагодари за науку. А говорить собеседнику, в ответ на желание помочь тебе решить твои проблемы, что собеседник дурак -- это обычное бытовое хамство. Фи, товарищ препод!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Кодт, Вы писали:
К>>Это значит — когда-то и где-то выстрелить в произвольный адрес памяти. И случайно угробить внутренние структуры менеджера кучи.
PD>Кстати, любопытный вопрос. Все, конечно, верно. Но почему мы то и дело слышим о попытках расстрелять кучу, но я почти не помню случаев, когда бы расстреляли стек — не около ESP, это добра навалом, а где-то в глубине ? То есть не выход инднекса за пределы, а просто пальнули по региону стека куда-нибудь. Эффект проявился бы так — в какой-то момент вместо возврата под точку вызова некоей функции управление передавалось бы черт знает куда с AV, конечно. Или испорчены были бы локальные данные. PD>И про расстрел статических данных я тоже что-то не помню.
Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций
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>Но ты, вместо того, чтобы переспросить то, что тебе трудно в этих трёх строчках понять, или обсудить то, что кажется тебе спорным, начинаешь ставить двойки. При этом сам ответа на свой вопрос даже не представляешь.
Ну-ну. Я вопрос задал, чтобы выслушать мнения других, а знаю ли я ответ на свой вопрос или нет — сделать этот вывод ты не можешь, поскольку я ничего о своем мнении не сказал.
>Так дискуссию приличные люди не ведут. Если тебе кажется, что я заблуждаюсь -- аргументированно развей сомнения.
Ну уж нет, с меня хватит. Аргументированно что-то делать в дискуссии с тобой — пустая трата времени и сил.
>Если заблуждаешься ты, то поблагодари за науку.
Я действительно заблуждался, принимая тебя до этого за человека, с которым можно о чем-то дискутировать. Благодарю за науку, что избавил меня от этого заблуждения.
Здравствуйте, Erop, Вы писали:
E>В отличии от кучи, запись в стек по устаревшему адресу довольно трудно организовать НЕПРЕДНАМЕРЕННО, а в статические данные вообще невозможно.
Здравствуйте, Sergey Chadov, Вы писали:
SC>Повезло просто в жизни Бывает все вышеперечисленное и даже гораздо веселее. Например, расстрел таблицы виртуальных функций
А хрен ли она не read-only? Типа из-за настройки адресов при загрузке?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>Смотри, стека в типичном приложении обычно резервируют метр. При этом ещё надо, чтобы он весь отмотался при работе приложения. Так что обычно стек и того меньше. Кучи в каком-нибудь нетяжёлом приложении обычно десятки метров максимум. Доступных по записи статических данных -- вообще мизер. Десятки килобайт возможно будет.
PD>М-да...
PD>int a[1000000]; PD>void main() PD>{ PD>}
Это, по твоему, типичное приложение, да?
E>>Обычно куча расстреливается совсем не так. Намного более реалистичный сценарий -- запись либо в освобождённый блок, либо недалеко от границы аллокированного. PD>С этим я согласен.
Тогда я не понимаю, чего ты не понимаешь... PD>Неужели ? ИМХО для этого достаточно сохранить указатель на локальную переменную и потом когда-нибудь им воспользоваться, когда стек будет, к несчастью, больше Не пробовал ?
1) Не пробовал. Я вообще стараюсь писать качественный код.
2) Для этого надо не просто дождаться момента, когда стек станет больше, но ещё и выйти сначала из той функции, на фрейме которой была создана та самая переменная. Это довольно хитрое стечение обстоятельств.
PD>Прелесть! Я эту фразу студентам повторять буду. Надо же иногда разрядку делать .
Я рад, что тебе весело, но попробуй понять, что тебе пишут.
PD>Я действительно заблуждался, принимая тебя до этого за человека, с которым можно о чем-то дискутировать. Благодарю за науку, что избавил меня от этого заблуждения.
Для "спасибо" тут есть кнопки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>М-да...
PD>>int a[1000000]; PD>>void main() PD>>{ PD>>}
E>Это, по твоему, типичное приложение, да?
Ох! Сил уже нет.
E>Тогда я не понимаю, чего ты не понимаешь...
Я все вполне понимаю, но сил с тобой дискутировать больше нет.
PD>>Неужели ? ИМХО для этого достаточно сохранить указатель на локальную переменную и потом когда-нибудь им воспользоваться, когда стек будет, к несчастью, больше Не пробовал ?
E>1) Не пробовал. Я вообще стараюсь писать качественный код.
E>2) Для этого надо не просто дождаться момента, когда стек станет больше, но ещё и выйти сначала из той функции, на фрейме которой была создана та самая переменная. Это довольно хитрое стечение обстоятельств.
Правильно мыслишь. Добавлю — не только выйти оттуда, но и зайти еще куда-то. Это само по себе отнюдь не хитрое стечение обстоятельств, и уж во всяком случае не более хитрое, чем запись по освобожденному указателю в куче. Строго говоря, это вообще практически эквивалентные ситуации. В обоих случаях речь идет о попытке записи туда, где раньше было то, что надо , но теперь уже нечто иное.
PD>>Я действительно заблуждался, принимая тебя до этого за человека, с которым можно о чем-то дискутировать. Благодарю за науку, что избавил меня от этого заблуждения.
E>Для "спасибо" тут есть кнопки
Увы, нет кнопки "Господи, помилуй". Минусы я ставить не очень люблю, а смайлики ставлю в основном по прямому назначению — когда мне действительно смешно. А тут плакать хочется
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;
}
Здравствуйте, Erop, Вы писали:
E> А говорить собеседнику, в ответ на желание помочь тебе решить твои проблемы, что собеседник дурак -- это обычное бытовое хамство.
Это не то чтобы хамство, это вы добровольно попали в треугольник Карпмана.