Зачем закрывать / тупить? (Windows) - PullRequest
8 голосов
/ 23 мая 2011

У меня есть процесс мониторинга изменений каталогов, который считывает обновления из файлов в наборе каталогов. У меня есть другой процесс, который выполняет небольшие записи во многие файлы в эти каталоги (тестовая программа). Рисунок около 100 каталогов с 10 файлами в каждом и около 500 файлов, изменяемых в секунду.

Через некоторое время процесс мониторинга каталогов зависает при вызове fclose() в методе, который в основном отслеживает файл. В этом методе я fopen() файл, проверяю правильность дескриптора, выполняю несколько операций поиска и чтения и затем вызываю fclose(). Все эти чтения выполняются одним и тем же потоком в процессе. После зависания нить никогда не прогрессирует.

Я не смог найти хорошую информацию о том, почему fclose() может зайти в тупик вместо того, чтобы возвращать какой-то код ошибки. В документации упоминается _fclose_nolock(), но она мне недоступна (Visual Studio 2003).

Зависание происходит как для отладочной, так и для релизной сборок. В отладочной сборке я вижу, что fclose() вызывает _free_base(), который зависает перед возвратом. Какой-то вызов в kernel32.dll => ntdll.dll => KernelBase.dll => ntdll.dll вращается. Вот сборка из ntdll.dll, которая зацикливается бесконечно:

77CEB83F  cmp         dword ptr [edi+4Ch],0 
77CEB843  lea         esi,[ebx-8] 
77CEB846  je          77CEB85E 
77CEB848  mov         eax,dword ptr [edi+50h] 
77CEB84B  xor         dword ptr [esi],eax 
77CEB84D  mov         al,byte ptr [esi+2] 
77CEB850  xor         al,byte ptr [esi+1] 
77CEB853  xor         al,byte ptr [esi] 
77CEB855  cmp         byte ptr [esi+3],al 
77CEB858  jne         77D19A0B 
77CEB85E  mov         eax,200h 
77CEB863  cmp         word ptr [esi],ax 
77CEB866  ja          77CEB815 
77CEB868  cmp         dword ptr [edi+4Ch],0 
77CEB86C  je          77CEB87E 
77CEB86E  mov         al,byte ptr [esi+2] 
77CEB871  xor         al,byte ptr [esi+1] 
77CEB874  xor         al,byte ptr [esi] 
77CEB876  mov         byte ptr [esi+3],al 
77CEB879  mov         eax,dword ptr [edi+50h] 
77CEB87C  xor         dword ptr [esi],eax 
77CEB87E  mov         ebx,dword ptr [ebx+4] 
77CEB881  lea         eax,[edi+0C4h] 
77CEB887  cmp         ebx,eax 
77CEB889  jne         77CEB83F 

Есть идеи, что здесь может происходить?

Ответы [ 2 ]

2 голосов
/ 01 июня 2011

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

Исходя из разборки, я предполагаю, что вы перезаписали некоторую внутреннюю структуру кучи, поддерживаемую ntdll, и она бесконечно выполняет итерацию по связанному списку.

В частности, в начале цикла текущий узел списка выглядит как ebx. В конце цикла ожидаемый последний узел (или терминатор, если хотите) выглядит немного как круглые списки, а последний узел совпадает с первым, указатель на этот узел имеет значение [edi+4Ch]) содержится в eax. Возможно, результат cmp ebx, eax никогда не будет равным, потому что в списке есть некоторый цикл, вызванный повреждением кучи.

Я не думаю, что это имеет какое-либо отношение к блокировкам, в противном случае мы увидим некоторые атомарные инструкции (например, lock cmpxchg, xchg и т. Д.) Или вызовы других функций синхронизации.

0 голосов
/ 03 июня 2017

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

Я также подозревал (1) имя дублирующегося файла (2) Планирование Windows (ввод-вывод файла не был завершен до запуска следующего шага задачи. Планирование Windows и многопоточность находятся за кулисами, поэтому это трудно проверить, но у меня есть похожая проблема, когда я пытался сохранить много данных в ASCII в цикле. В этом случае решено сохранение в двоичном формате.)

Моя среда, IDE: Visual Studio 2015,ОС: Windows 7, язык: C ++

...