Cледующая не хорошая ситуация..: тривиальный код (дефайны заменены на числа, с ними все в порядке): Код (Text): heap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 100*15*12, 0); // выделяет обычно 0x00380000 (0x00400000 - ImageBase) // память доступна по 0x00384FF0 /*.......... потом вызов другой ф-ии (HANDLE heap передается), внутри неё: */ // allocate memory new_heap=HeapAlloc(heap, HEAP_ZERO_MEMORY, 100*12); При первом аллоке возвращает 0x00381EA0 - это понятно. При втором: Unhandled exception at 0x7c93b4ed (ntdll.dll) in [blah.exe]: 0xC0000017: Not Enough Quota. MSDN говорит: "Error Message: (Not Enough Quota) Not enough virtual memory or paging file quota is available to complete the specified operation. User Action: This is a Windows 2000 Executive STATUS error message. Try running the application again. If this message reappears, contact your system administrator to adjust your paging file size or your quota." Гугл говорит, что надо поискать другие пути выделения памяти, потому что происходит утечка памяти.. (% Естественно, если создать чистый проект и выделять подобным образом память - все четко. Проект не такой уж большой.. Даже не средний. Скорее чуть больше, чем маленький) Кто сталкивался? В одном вялом обсуждении нашел что-то про PGFLQUOTA или PQL_DPGFLQUOTA. Я запускаю под админом, при чем на разных компах - результат тот-же. Если юзать malloc - проблема та-же.
Пожалуйста. Это кусочек парсера импорта. heap, как я уже говорил, был выделен ранее. Никакой работы памятью больше нету. Даже не знаю, чем поможет листинг.. но раз пр0сите: Код (Text): DWORD read_import(PEF_PTRS ef_ptrs, void *ptr_img, HANDLE heap) { /* Читает импорт одного файла и заполняет соответствующие структуры lyb_entry's. */ char *lib_name[20]; BOOL exist = FALSE; PLIB_LIST_ENTRY lib_entry; PIMAGE_IMPORT_DESCRIPTOR Import = \ (PIMAGE_IMPORT_DESCRIPTOR) \ ((((PIMAGE_NT_HEADERS) \ ((((PIMAGE_DOS_HEADER)ptr_img)->e_lfanew)+ \ (int)ptr_img))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)+ \ (int)ptr_img); while (Import->Characteristics) // main cycle { strcpy((char *)lib_name,(char *)((Import->Name)+(int)ptr_img)); strlwr((char *)lib_name); if (must_dll((char *)lib_name)) { lib_entry = ef_ptrs->ptr_lib_entrys; // Is lib entry already in list? // for (int i = 0; i < ef_ptrs->lib_entrys_count; i++) { if (!(strcmp(lib_entry->lib_name,(char *)lib_name))) { exist=TRUE; lib_entry->counter++; // up library rate break; } // if lib_entry++; } // for if (!exist) // create new entry { strcpy(ef_ptrs->ptr_lib_names + ef_ptrs->lib_names_size,(char *)lib_name); lib_entry->lib_name = ef_ptrs->ptr_lib_names + ef_ptrs->lib_names_size; ef_ptrs->lib_names_size += strlen((char *)lib_name)+1; lib_entry->counter = 0; // allocate memory fo API_LIST_ENTRY [b]lib_entry->ptr_api_list=(PAPI_LIST_ENTRY)HeapAlloc(heap, HEAP_ZERO_MEMORY, MAX_API*sizeof(API_LIST_ENTRY));[/b] if (!lib_entry->ptr_api_list) return(ERROR_INVALID_ADDRESS); lib_entry->api_list_count=0; ef_ptrs->lib_entrys_count++; } // ********************** // The lib_entry is set up. Read them. // read_import_descriptor(ef_ptrs, Import, (DWORD)ptr_img, lib_entry); } // end if (must dll) Import++; // next IMAGE_IMPORT_DESCRIPTOR entry } // main cycle return 1; //копибара отсюдава }
Предполагаю, что цикл в read_import бегает дольше чем необходимо, и просто тупо выжирается вся доступная память.
Да хоть на 10м. Проблема в ф-ции read_import, больше ей негде быть ( из тех данных, что приведены ). Статус STATUS_NO_MEMORY говорит нам, что либо поврежден хип, либо недостаточно памяти ( что вернее всего ). Советую отладчиком пройтись по этой ф-ции и посмотреть, что конкретно там не так.
Кстати, если куча создана с флагом HEAP_GENERATE_EXCEPTIONS, то неплохо было бы исключения то ловить всеже, иначе зачем ставить флаг.
Ты думаешь я не отлаживал ф-ию прежде чем создать топик на форуме? Ф-ия не работет с памятью и не выделяет её более 1-го раза. При второй попытке происходит крэш. На данный момент код тестовый. Я пробовал все флаги. Разницы совершенно никакой. Под отладкой все видно.
Всмысле куча повреждена, например если в ф-ции read_import_descriptor (куда передается указатель на структуру содержащую выделенную память) есть запись блока данных размером больше чем MAX_API*sizeof(API_LIST_ENTRY).
А, понятно.. А разве в таком случае не произойдет экспшна при попытке записи выше кучи? Сейчас не могу посмотреть, к сожалению. По-идее не должно быть такого, т.к. там было всего-лишь 15 ф-ий, а 15*sizeof(API_LIST_ENTRY)=180, а выделяется под одну библиотеку 1200. Но, конечно, завтра проверю.
icent Хип не следует юзать. Выделяйте память сервисами(NtAllocateVirtualMemory) либо через экспорт/стуб Zw* Ваша ошибка довольно редкая, обойти её не удастся, если в ядре не достаточно памяти, тогда можно попытаться использовать секции(дисковое пространтсво, своп).
Clerk Т.е. баг кроется в фантиках kernel32.dll для NtAllocateMemory? Да.. вспомнилось: Правда, иногда возникают сложные проблемы. Я вижу, как они появляются, я останавливаюсь, я наблюдаю. Затем я меняю одну строку кода и сложности исчезают, как клуб дыма. [C] James Geoffrey
icent Хип это громоздкая не стабильная и кривая обертка вокруг сервисом выделяющих память, не вижу смысла её применять.
у тебя голова нестабильная и кривая. icent TSS прав почти 100% ошибка в read_import_descriptor(). Эксцепшн произойдет при попытке освобождения испорченной кучи. Может еще в других случаях - это надо конкретно смотреть как реализована куча в конкретной системе. В разных по-разному очень.
Завтра заноплю вызов read_import_descriptor() и посмотрим что будет. Вообще-то хип юзается самой виндой.. так что код все-же перепроверю.
HeapAlloc честно расширяла память на столько, насколько могла Ее не в чем винить (ошибка была в коде read_import_descriptor), так что надстройки кернел32 не виноваты. TSS, SashaTalakin, Clerk, спасибо. p.s. Aqilla, все, что в теге code не проверяется на мат? x)