Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > new возвращает NULL


Автор: bel_nikita 30.1.2006, 17:58
MSVC 6 SP6/ PharLap

Такая засада: оператор new возвращает NULL smile Чтобы это могло быть?
До конструктора не доходит, HeapAlloc выдает NULL
Интересно то, что, если прога идет по другой ветке, то все ок.

Автор: azesmcar 30.1.2006, 18:43
интересно smile

насчет HeapAlloc -а это debug-ом выяснялось или пробовал сам HeapAlloc вызывать???

можно задать параметр HEAP_GENERATE_EXCEPTIONS, и посмотреть...вместо возвращения NULL он выдаст exception...

Автор: threef 30.1.2006, 18:50
Код

struct null{
    bool s;
};
main()
{
    int x=5,y=7;    
    x==y? x++ :
    ( x>y ? x++: *(&y-1)=-1),y++;
    null *z = new null[x];
    cout<<z<<'\n';
}



Может, немного кода ?
Ну очень трудно догадаться. Здесь new тоже NULL

Автор: DeadSoul 31.1.2006, 00:47
Цитата(bel_nikita @ 30.1.2006, 17:58 Найти цитируемый пост)

Чтобы это могло быть?

Более 4-х лет боевого опыта. Не бывает такого
Добавлено @ 00:57
bel_nikita, а ты не массив пытаешься создать?
Код

A* pA=new A[mySize];// а mySize меньше нуля....

Автор: bel_nikita 31.1.2006, 01:08
Цитата(DeadSoul @ 30.1.2006, 23:47)
Более 4-х лет боевого опыта. Не бывает такого

Бывает оказывается smile возвращает нуль smile У меня, как-то был похожий трабл, реально памяти нехватало, но тут свободной 250 МБ. Но самое непонятное, то что по одной ветке программы все работает, по-другой нет.
А код совершенно безобидный:
Код

...
CObject* pObject = new CObject();
...

Автор: DeadSoul 31.1.2006, 01:32
Минимальный код воспроизодящий ошибку сделать нереально насколько я понимаю.

operator new переопределен?

Попробуй полный ребилд, может дебугер нсовсем то отображает

Автор: JackYF 31.1.2006, 03:03
А какое вообще право имеет new возвращать NULL???

Если я не ошибаюсь, по стандарту он ОБЯЗАН вызывать исключение. Или я чего-то недопонял?

Насчет самой проблемы - не бывало.

Автор: bel_nikita 31.1.2006, 09:41
Цитата(JackYF @ 31.1.2006, 02:03)
А какое вообще право имеет new возвращать NULL???

Если я не ошибаюсь, по стандарту он ОБЯЗАН вызывать исключение. Или я чего-то недопонял?

Возвращать NULL - это фича MSVC

Автор: Mayk 31.1.2006, 14:17
Цитата(bel_nikita @ 31.1.2006, 13:41 Найти цитируемый пост)

Возвращать NULL - это фича MSVC

Как насчёт того, чтобы переопределить new самому таким образом, чтобы он кидал исключения?

Автор: threef 31.1.2006, 15:54
new...
Цитата


bel_nikita

Возвращать NULL - это фича MSVC



Возвращать NULL- это фича new.
Честно говоря, если у тебя new для CObject не переопределен, то неясно, как он возвращает NULL. У меня не получилось smile

Автор: Mayk 31.1.2006, 16:47
Цитата(threef @ 31.1.2006, 19:54 Найти цитируемый пост)

Возвращать NULL- это фича new.

это вовсе не фича new, это фича new(nothrow).
Стандарт 2003. Параграф 5.3.4. Пункт 13.
Цитата

[Note: unless an allocation function is declared with an empty exception-specification (15.4), throw(), it
indicates failure to allocate storage by throwing a bad_alloc
exception (clause 15, 18.4.2.1); it returns a
non-null pointer otherwise
. If the allocation function is declared with an empty exception-specification,
throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise. ] If the
allocation function returns null, initialization shall not be done, the deallocation function shall not be called,
and the value of the new-expression shall be null.

Иными словами - обычный new либо возвращает не null, либо кидает исключение.

Автор: Romikgy 31.1.2006, 16:57
Где то читал , что это настраивается компилятором, что делать, или нулл возвращать или исключение кидать.

Автор: Earnest 31.1.2006, 16:59
Стандарт - это, конечно, хорошо, но не в идеальном мире живем...
Насколько я помню, в 6й студии была такая опция - NULL возвращать или исключение кидать.
Вот как и где она включается - не помню - то ли что-то вызвать надо, то ли просто опция в проекте или слово волшебное для препроцессора... Короче, попробуй поискать в MSDN (именно том, что для этой студии) по словам new, set_new_handler и т.д. (просто чтобы понять - что же у тебя включено).

Тем не менее, очень странно, что возвращает NULL (не 256 mb твой объект ведь)... Попробуй сходить внутрь отладчиком.

Кажется, new может вернуть NULL, если просят 0 байтов... Чудно, конечно, но надо бы проверить, чего там в той ветке компилятор накомпилировал...

Автор: np9mi7 31.1.2006, 17:23
Цитата
Интересно то, что, если прога идет по другой ветке, то все ок.

Цитата
Но самое непонятное, то что по одной ветке программы все работает, по-другой нет.

Что за ветки ты имеешь ввиду?

Автор: bel_nikita 31.1.2006, 18:43
Сваливается событие в глобальную очередь, потом парсится:
Код
BOOL cTestManager::ProcessMessage(Message timMsg)
{
...
case CREATE:
          InitTDispatcher();
break;
...
}

Происходит инициализация диспетчера:
Код
BOOL InitTDispatcher(int iPar = -1)
{
...
    TRegistrator::Instance()->ParseCreationXMLFile("module.xml");
...
}

А вот, соббственно и проблемная "зона":
Код

bool TRegistrator::ParseCreationXMLFile(const char *szFileName)
{
  CXMLRead *lpXML = new CXMLRead(); // Вот, тут я получаю  NULL
...
}

Покопался в дебаге. NULL вылает метод HeapAlloc.

Автор: Earnest 31.1.2006, 19:59
Почитай в MSDN насчет HeapAlloc. Она может возвращать 0 в двух случаях: если нет памяти, или если хип поврежден. Полагаю, дело во-втором.
Как я поняла, один и тот же код (ParseCreationXMLFile) у тебя то работает, то нет, в зависимости от того, по какой ветви идет выполнение? Так проверь как следует ветку, в которой рушится. Посмотри функции HeapValidate, HeapQueryInformation, HeapWalk.

Автор: Fixin 31.1.2006, 20:14
А может скобки убрать при объявлении?
Код

bool TRegistrator::ParseCreationXMLFile(const char *szFileName)    
{    
  CXMLRead *lpXML = new CXMLRead;
...    
}

Автор: Earnest 31.1.2006, 20:47
Скобки там, конечно, не нужны, но вряд ли это они производят такой разрушительный эффект на хип smile

Автор: Fixin 31.1.2006, 21:30
А хто знает? шестая ведь...

Автор: maxim1000 31.1.2006, 21:42
многопоточность используется?

Автор: bel_nikita 31.1.2006, 21:52
Цитата(Earnest @ 31.1.2006, 18:59)
Она может возвращать 0 в двух случаях: если нет памяти, или если хип поврежден. Полагаю, дело во-втором.

Вот, и я так думаю. Но отыскать, где разрушаю, уже неделю не могу. Все работает замечательно имеено до момента указанного выделения.

Цитата(maxim1000 @ 31.1.2006, 20:42)
многопоточность используется?

Да, используется. до 15 потоков.

Автор: dronzo 31.1.2006, 22:36
bel_nikita, Здесь обсуждается похожая проблема. Я честно пытался понять до конца, так как самому интересно стало, но ... smile Быть может, так как ты занимаешься своей проблемой уже определённое время, то приведённые советы будут яснее :
http://groups.google.ru/group/microsoft.public.vc.language/browse_thread/thread/c6915d3bddf86dfe/4892c08b35aac700?tvc=2#4892c08b35aac700

Автор: chipset 31.1.2006, 22:37
Код

bool TRegistrator::ParseCreationXMLFile(const char *szFileName)
{


try {  CXMLRead *lpXML = reinterpret_cast<CXMLRead*> (HeapAlloc(GetProcessHeap(),HEAP_GENERATE_EXCEPTIONS,sizeof(CXMLRead))); // /
{ catch (STATUS_NO_MEMORY)
{
//отрепорть как-нить
{
}

Добавлено @ 22:39
Попробуй, что бы было ясно что дело не в outofmemory.
Добавлено @ 22:40
А класс CXMLRead самописный? Может трабла в его конструкторе?

Автор: maxim1000 31.1.2006, 23:33
Цитата(bel_nikita @ 31.1.2006, 20:52 Найти цитируемый пост)

Да, используется. до 15 потоков

у HeapCreate есть один флажок: HEAP_NO_SERIALIZE
возможно, по каким-то причинам он устанавливается
правда, не знаю, как это проверить - никогда не сталкивался с необходимостью узнать параметры кучи
если все-таки это так (может, где-то по умолчанию стояло однопоточное приложение), то я вижу три варианта:
1. для каждого потока сделать свою кучу (ну мало ли)
2. найти способ убрать флаг HEAP_NO_SERIALIZE, еслине ошибаюсь, этим занимается CRT...
3. использовать HeapLock и HeapUnlock

Автор: Earnest 1.2.2006, 09:51
Цитата(bel_nikita @ 31.1.2006, 21:52 Найти цитируемый пост)

Вот, и я так думаю. Но отыскать, где разрушаю, уже неделю не могу.

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

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

Автор: bel_nikita 9.2.2006, 13:13
Никак не удается найти smile

Автор: Hroft 9.2.2006, 17:47
А если прямо перед этой строчкой написать какое-нибудь банальное
Код

        int* iii = new int;
        *iii = 4;
        int ii = *ii;

оно будет работать? Мне тоже кажется, что проблема в конструкторе. Даже если не самописный, не боги горшки обжигают.

Автор: bel_nikita 9.2.2006, 18:23
Вот, такой дефайн пробывал вставлять, чтоб отловить куски, где хип "бью".
Код
#define ASSERT_NEW_OK  { char* __p = new CHAR[6400]; if ( __p == NULL ){ __asm { int 3 }; } else delete __p; }

Но сейчас "покапался" в линкере и нашел переменную stack. Увеличил до 32768 и ... Ура! Работает!... Вроде smile

Автор: Hroft 9.2.2006, 19:11
У тебя там что, рекурсивные вызовы есть, что стека не хватает? Или такие прикольные локальные переменные?
Интересно, а stack общий для всех потоков, или каждому свой?

Автор: Lotrex 10.2.2006, 08:57
Цитата

Цитата(threef @  31.1.2006,  19:54 Найти цитируемый пост)

Возвращать NULL- это фича new.

это вовсе не фича new, это фича new(nothrow).
Стандарт 2003. Параграф 5.3.4. Пункт 13.
Цитата

[Note: unless an allocation function is declared with an empty exception-specification (15.4), throw(), it
indicates failure to allocate storage by throwing a bad_alloc
exception (clause 15, 18.4.2.1); it returns a
non-null pointer otherwise
. If the allocation function is declared with an empty exception-specification,
throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise. ] If the
allocation function returns null, initialization shall not be done, the deallocation function shall not be called,
and the value of the new-expression shall be null.

Иными словами - обычный new либо возвращает не null, либо кидает исключение.


А мне бы как раз такой необычный new не помешал. Из приведенной цитаты стандарта понятно, что вроде можно это сделать, но не понятно, как... Мож, подскажете?

Автор: Mayk 10.2.2006, 09:06
Цитата(Lotrex @ 10.2.2006, 12:57 Найти цитируемый пост)


А мне бы как раз такой необычный new не помешал. Из приведенной цитаты стандарта понятно, что вроде можно это сделать, но не понятно, как... Мож, подскажете?

Код

#include <new>
#include <iostream>
using namespace std;
int main()
{
   char * c = new(nothrow) char[0x7FFFFFFF];
   if(c==0){ 
      cout << "null!" << endl;
   }
}


Автор: np9mi7 10.2.2006, 09:21
Цитата
Но сейчас "покапался" в линкере и нашел переменную stack. Увеличил до 32768 и ... Ура! Работает!... Вроде smile
, одно не понятно: стек и хип разные вещи, как это могло сработать...???

Автор: Hroft 10.2.2006, 11:57
В конструкторе могли локальные переменные объявляться, они его и забили окончательно.

Автор: np9mi7 10.2.2006, 12:28
Цитата
В конструкторе могли локальные переменные объявляться, они его и забили окончательно.
, тогда словил бы exception о том, что стек переполнен, так причем тут куча?

Автор: Hroft 10.2.2006, 12:55
И правда...
А может, он не смог это исключение кинуть, поскольку оно создается в стеке, а он переполнен? smile
Или сам new использует локальные переменные зачем-то, и в этом проблема? Тоже сильно сомнительно...

Автор: Neitron 10.2.2006, 13:02
Стандарт гарантирует что в стеке всегда будет место для этого исключения.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)