повреждение функции vector.resize памяти, когда размер является слишком большим

Я использую рекурсивный вызов для хождения по цепочке управления. Добавьте это к своему управлению.

public Form ParentForm
{
    get { return GetParentForm( this.Parent ); }
}

private Form GetParentForm( Control parent )
{
    Form form = parent as Form;
    if ( form != null )
    {
        return form;
    }
    if ( parent != null )
    {
        // Walk up the control hierarchy
        return GetParentForm( parent.Parent );
    }
    return null; // Control is not on a Form
}

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

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

6
задан Dima 27 October 2009 в 17:19
поделиться

3 ответа

I think that vector::max_size() is pretty much always a 'hard coded' thing - it's independent of how much memory the system/library is prepared to dynamically allocate. Your problem seems to be a bug in the vector implementation that corrupts things when an allocation fails.

'Bug' might be too strong of a word. vector::resize() is defined in terms of vector::insert() and the standard says this about vector::insert():

If an exception is thrown other than by the copy constructor or assignment operator of T there are no effects

So it seems like there may be times when the resize() operation is allowed to corrupt a vector, but it would still be nice if the operation were exception safe (and I think it wouldn't be out of line to expect the library to do that, but maybe it's harder than I imagine).

You seem to have a couple reasonable options:

  • change or update to a library that doesn't have the corruption bug (what compiler/library version are you using?)
  • instead of checking against vector::max_size() set nMaxSize to your own reasonable maximum and do what you have above but using that threshold instead.

Edit:

I see that you're using VC6 - there's definitely a bug in vector::resize() that might have something to do with your problem, though looking at the patch I honestly don't see how (actually it's a bug in vector::insert(), but as mentioned, resize() calls insert()). I'd guess it would be worthwhile to visit Dinkumwares' page for bug fixes to VC6 and apply the fixes.

The problem might also have something to do with the patch on that page - it's unclear what the bug is that's discussed there, but vector::insert() does call _Destroy() and vector<> does define the name _Ty so you might be running into that problem. One nice thing - you won't have to worry about managing the changes to the headers, as Microsoft is never touching them again. Just make sure the patches make it into version control and get documented.

Note that Scott Meyers in "Effective STL" suggests using SGI's or STLPort's library to get better STL support than comes with VC6. I haven't done that so I'm not sure how well those libraries work (but I also haven't used VC6 with STL very much). Of course, if you have the option to move to a newer version of VC, by all means do it.


One more edit:

Thanks for the test program...

VC6's _Allocate() implementation for the default allocator (in ) uses a signed int to specify the number of elements to allocate, and if the size passed in is negative (which apparently is what you're doing - certainly in the test program you are) the _Allocate() function forces the requested allocation size to zero and proceeds. Note that a zero-sized allocation request will pretty much always succeed (not that vector checks for a failure anyway), so the vector::resize() function merrily tries to move its contents into the new block, which isn't quite big enough to say the least. So the heap gets corrupted, it'll likely hit a invalid memory page, and regardless - your program is hosed.

So the bottom line is don't ever ask VC6 to allocate more than INT_MAX objects in one go. Probably not a great idea in most circumstances (VC6 or otherwise).

Also, you should keep in mind that VC6 uses a pre-standard idiom of returning 0 from new when an allocation fails rather than throwing bad_alloc.

5
ответ дан 8 December 2019 в 17:23
поделиться

Я НАСТОЯТЕЛЬНО предлагаю вам проверять свои данные на наличие повреждений ПЕРЕД вызовом библиотечных функций с, возможно, неправильными аргументами!

Используйте какой-то хэш-код или алгоритм проверки суммы для ваших пакетов. Вы не можете рассчитывать на то, что библиотека вам поможет, поскольку она не может: Возможно, вы дадите ему поврежденный, но все еще действующий (с точки зрения библиотеки) размер, который действительно велик, поэтому он выделяет, например, 768 МБ ОЗУ. Это может сработать, если в системе достаточно свободной памяти, но может выйти из строя, если на вашем компьютере размером 1024 МБ работают другие программы, которые потребляют слишком много памяти.

Итак, как сказано выше: Сначала проверьте!

5
ответ дан 8 December 2019 в 17:23
поделиться

Я понятия не имею, что вы имеете в виду, когда говорите «изменение размера повредило память». Как вы это определяете?

FWIW, я не согласен с ответом Майкла . Если std :: vector <> :: resize () вызывает расширение вектора, я вижу две возможности:

  1. Либо один из конструкторов, используемых для заполнения нового пространства (или копирования элементов), либо
  2. распределитель, используемый для увеличения вектора, сделал
  3. или вектор, который заранее определил, что запрошенный размер слишком велик, и выбрасывает.

С помощью std :: vector мы можем безопасно отклонить №1, так что остается №2. Если вы не t использовать какой-либо специальный распределитель, тогда следует использовать std :: allocator и, AFAIK, который вызовет new для выделения памяти. И новый выбросит std :: bad_alloc . Однако вы говорите, что не можете этого поймать, поэтому я не знаю, что происходит.

Что бы это ни было, оно должно быть производным от std :: exception , чтобы вы могли сделать это, чтобы узнать:

try {
  my_vec.resize( static_cast<std::size_t>(-1) );
} catch(const std::exception& x) {
  std::cerr << typeid(x).name() << '\n';
}

Что это в результате?

В любом случае, что бы это ни было, Я почти уверен, что это не должно испортить память. Либо это ошибка в вашей реализации std lib (маловероятно, если вы спросите меня, если вы не используете очень старую версию), либо вы сделали что-то не так в другом месте.


Отредактируйте теперь, когда вы сказали, что используете VS6 ...

Вы должны были сказать это раньше. VC6 был выпущен более десяти лет назад, после того, как М.С. проиграли свой голос в комитете std, потому что они слишком долго не появлялись на собраниях. Реализация std lib, которую они отправили, была от Dinkumware (хорошая), но из-за юридических проблем она была для VC5 (очень плохо), в которой было много мелких и крупных ошибок и даже не было поддержки шаблонов участников, хотя компилятор VC6 поддержал это. Честно говоря, чего вы ждете от такого старого продукта?

Если вы не можете переключиться на достойную версию VC (я бы порекомендовал хотя бы VC7.1, также известный как VS.NET 2003, поскольку именно эта версия сделала большой скачок в сторону соответствия стандарту), по крайней мере, посмотрите, Dinkumware до сих пор продают VC6t-версию своей превосходной библиотеки. (На самом деле, я был бы удивлен, но раньше они были, и мало ли ...)

Что касается исключений: В более ранней версии VC (это включает VC6 и не включает VC8 aka VS.NET 2005, хотя я не уверен насчет VC7.1) по умолчанию нарушения доступа могли быть пойманы с помощью catch (...) . Так что, если такой блок catch что-то поймает, вы не узнаете, было ли это исключением C ++. Я бы посоветовал использовать catch (...) только вместе с throw; , чтобы исключение прошло. Если вы это сделаете, вы получите настоящий сбой в AV и сможете отслеживать их в отладчике. Если вы этого не сделаете, антивирус будет проглочен, и тогда вы застрянете с приложением, которое пришло в ярость, даже если вы не знали. Но делать что-либо, кроме прерывания работы с AV-приложением, не имеет смысла. AV является одним из результатов неопределенного поведения , и после этого все ставки отменяются.

4
ответ дан 8 December 2019 в 17:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: