Вверх ↑
Этот топик читают: Гость
Ответов: 3889
Рейтинг: 362
#1: 2011-06-28 13:32:55 ЛС | профиль | цитата
nesco писал(а):
Маленький диспетчер задач на основе консольной программы tasklist
WinXPSP3 P4 HT 512RAM с админскими правами, вылетает с разными фатальными ошибками после нескольких циклов. Иногда компиляторный перехват ошибок успевает сработать первым (ошибка 204 - неправильно отработал указатель), иногда я уже в дебаггере вижу, что используется недопустимый указатель при косвенной адресации через регистр EAX в одном и том же месте. Если интересно, могу декомпилировать и выяснить в каком классеюните лежит этот код.
------------ Дoбавленo в 12.54:
Как и обещал, ориентируясь по остаточным данным (символьным меткам имён в коде) разобрал в дизассемблере объектное дерево. Вылетает процедура DeleteFree(f:Pfree) из system. Надо думать, проблема проявляется в менеджере памяти, но вот откуда она берёт начало... Сейчас прослежу дерево вызовов по стеку, постараюсь сказать, откуда ноги растут.
------------ Дoбавленo в 13.32:
Фатальная цепочка, полученная методом дедукции (читаю стек, ищу начало процедуры, её дискриптор, там читаю символьное имя), выглядит так hiWinExec -> LStrFromPCharLen -> NewAnsiString -> GetMem -> SysGetMem -> TryHarder -> DeleteFree -> ошибка

Предварительно ошибка происходит в модуле hiWinExec, строка 125: pBuffer[Total] := #0;

Что интересно, вылетает под обоими компиляторами.

карма: 1

0
Разработчик
Ответов: 26170
Рейтинг: 2127
#2: 2011-06-28 13:36:50 ЛС | профиль | цитата
1nd1g0 писал(а):
WinXPSP3 P4 HT 512RAM с админскими правами, вылетает с разными фатальными ошибками после нескольких циклов

Оригинально, а в Семерке работает исправно. Я с полчаса гонял, ни пожирания памяти, ни вылетов замечено не было
карма: 22

0
Ответов: 1841
Рейтинг: 369
#3: 2011-06-28 13:48:05 ЛС | профиль | цитата
Подтверждается
Часто раньше сталкивался с этой проблемой в различных ОС (xp-7)...

p.s. если после запуска схемы nesco зажав кнопку "вниз" быстро клацать по списку процессов то программа вылетает почти сразу же...
карма: 1
0
Разработчик
Ответов: 26170
Рейтинг: 2127
#4: 2011-06-28 13:56:50 ЛС | профиль | цитата
1nd1g0, попробуй вот такой код в компоненте WinExec



procedure THIWinExec.Read;
var Total:dword; bWait:boolean; hWait:THandle; bError:boolean;
// pBuffer: array[0..1024] of char;
pBuffer: string;
begin
pBuffer := ';
hWait := CreateEvent(nil,false,false,nil); bError := false;
while FRead and not bError do begin
bWait := true;
if not PeekNamedPipe(hPipeErrorsRead,nil,0,nil,@Total,nil) then bError := true;
if Total>0 then begin
bWait := false;
SetLength(pBuffer, Total);
if ReadFile(hPipeErrorsRead, pBuffer[1], Total, Total, nil) then begin
// pBuffer[Total] := #0;
_hi_OnEvent(_event_onConsoleError, pBuffer);
end;
end;
if not PeekNamedPipe(hPipeOutputRead,nil,0,nil,@Total,nil) then bError := true;
if Total>0 then begin
bWait := false;
SetLength(pBuffer, Total);
if ReadFile(hPipeOutputRead, pBuffer[1], Total, Total, nil) then begin
// pBuffer[Total] := #0;
_hi_OnEvent(_event_onConsoleResult, pBuffer);
end;
end;
if bWait then WaitForSingleObject(hWait,1);
end;
CloseHandle(hWait);
if bError then begin
Terminate;
_hi_OnEvent(_event_onConsoleTerminate);
end;
end;
------------ Дoбавленo в 13.56:
г. ость писал(а):
ещё бы так назойливо не мигало

Так то частая перерисовка. Можно попробовать полечить Label-ом с нулевым размером и включенной прозрачностью
карма: 22

0
Ответов: 1841
Рейтинг: 369
#5: 2011-06-28 14:01:58 ЛС | профиль | цитата
nesco писал(а):
попробуй вот такой код в компоненте WinExec

теперь всё нормально
------------ Дoбавленo в 14.01:
а нет, вылетает
карма: 1
0
Разработчик
Ответов: 26170
Рейтинг: 2127
#6: 2011-06-28 14:17:06 ЛС | профиль | цитата
CriDos писал(а):
а не, вылетает

На чем вылетает, то может проблема не в WinExec

Попробуй на обычной таблице

code_24509.txt
------------ Дoбавленo в 14.17:
Я подозреваю, что проблема кроется в другом. Тут мы пытаемся запустить второе консольное приложение, поверх незаконченного предыдущего с переназначением оверлэпида. Интересно, а вот такой пример вылетает



Add(MainForm,2953706,63,147)
{
Width=793
Height=577
Caption="TaskList"
link(onCreate,6353601:doWork2,[])
}
Add(Charset,1075513,273,154)
{
link(onCharset,6222339:doAdd,[])
}
Add(StrList,6222339,336,154)
{
}
Add(Replace,10589290,336,217)
{
SubStr="1310"
link(onReplace,9502237:doReplace,[])
link(Str,6222339:Text,[])
}
Add(Replace,9502237,385,217)
{
SubStr=""""
DestStr="1310"
link(onReplace,1642398:doReplace,[])
}
Add(Hub,8537244,483,217)
{
OutCount=6
link(onEvent1,10397504:doText,[])
link(onEvent3,2320706:doClear,[(615,237)(615,279)])
link(onEvent4,10125348:doEnum,[(531,244)(531,272)])
link(onEvent5,6222339:doClear,[(509,251)(509,121)(318,121)(318,167)])
link(onEvent6,8016477:doConsoleTerminate,[(515,258)(515,288)(177,288)(177,174)])
}
Add(Replace,1642398,434,217)
{
SubStr="""
link(onReplace,8537244:doEvent1,[])
}
Add(Timer,15011779,133,161)
{
Interval=100
Enable=1
AutoStop=1
link(onTimer,8016477:doConsoleExec,[])
}
Add(Timer,11250468,273,217)
{
Interval=400
Enable=1
AutoStop=1
link(onTimer,10589290:doReplace,[])
}
Add(WinExec,8016477,196,147)
{
Param="/V /NH /FO CSV"
FileName="tasklist"
Point(doConsoleExec)
Point(onConsoleResult)
Point(doConsoleTerminate)
Point(onConsoleTerminate)
link(onExec,11250468:doTimer,[(258,153)(258,223)])
link(onConsoleResult,1075513:doCharset,[])
link(onConsoleTerminate,6353601:doWork1,[(240,167)(240,128)(116,128)])
}
Add(StrList,10397504,560,196)
{
}
Add(ArrayEnum,10125348,574,266)
{
link(onItem,2320706:doAdd,[])
link(Array,10397504:Array,[])
}
Add(StringTable,2320706,630,266)
{
Left=565
Top=115
Align=5
Columns=#10:Имя образа|3:PID|10:Имя сессии|12:№ сеанса===2|6:Память|9:Состояние|12:Пользователь|12:Время ЦП===2|14:Заголовок окна|
StrDelimiter=","
}
Add(HubEx,6353601,112,161)
{
link(onEvent,15011779:doTimer,[])
}

карма: 22

0
файлы: 1code_24509.txt [1.6KB] [206]
Ответов: 3889
Рейтинг: 362
#7: 2011-06-28 14:23:39 ЛС | профиль | цитата

Такое - не вылетает:

code_24510.txt
------------ Дoбавленo в 14.23:
Такое - вылетает


Add(WinExec,8016477,252,140)
{
Param="/V /NH /FO CSV"
FileName="tasklist"
Point(doConsoleExec)
Point(onConsoleResult)
}
Add(Timer,15011779,105,154)
{
Interval=500
link(onTimer,8016477:doConsoleExec,[])
}

карма: 1

0
файлы: 1code_24510.txt [385B] [141]
Ответов: 1841
Рейтинг: 369
#8: 2011-06-28 14:24:00 ЛС | профиль | цитата
Запустил сразу все 3 схемы, 1 и 2 вылетели почти сразу, 3 вариант вроде до сих пор работает нормально
карма: 1
0
Ответов: 3889
Рейтинг: 362
#9: 2011-06-28 14:24:58 ЛС | профиль | цитата
CriDos, последний вариант работает потому, что таймер останавливается сразу же и ждёт.
карма: 1

0
Ответов: 1841
Рейтинг: 369
#10: 2011-06-28 14:26:54 ЛС | профиль | цитата
1nd1g0 писал(а):
Такое - не вылетает:
Такое - вылетает

странно, у меня обе работают нормально
карма: 1
0
Разработчик
Ответов: 26170
Рейтинг: 2127
#11: 2011-06-28 14:28:16 ЛС | профиль | цитата
1nd1g0 писал(а):
последний вариант работает потому, что таймер останавливается сразу же

Скорее, не по-этому, а потому, что я завершаю консольное приложение и метод оверлэпида отрабатывет до конца, те завершает свой вызов в стеке
карма: 22

0
Ответов: 3889
Рейтинг: 362
#12: 2011-06-28 14:29:21 ЛС | профиль | цитата
Вылет происходит именно там, где я указал - в присвоении динамическому массиву символов нолика. Виноват менеджер памяти, по какой-то причине после отработки одной инстанции процедуры THIWinExec.Read менеджер памяти удаляет ВСЕ динамические массивы для ВСЕХ экземпляров функций в параллельных потоках
карма: 1

0
Разработчик
Ответов: 26170
Рейтинг: 2127
#13: 2011-06-28 14:33:41 ЛС | профиль | цитата
1nd1g0 писал(а):
Такое - вылетает

Это не таймер виноват, а запущенное консольное приложение без его остановки
------------ Дoбавленo в 14.32:
1nd1g0 писал(а):
Вылет происходит именно там, где я указал - в присвоении динамическому массиву символов нолика

Я заменил этот код на другой, и CriDos его проверил, он тоже вылетает. Вмноват не нолик, а незавершенный оверлэпид. Оверлэпид -- асинхронный метод, с ним надо работать как с потоком, те сначала обязательно завершить, перед тем, как назначать новый
------------ Дoбавленo в 14.33:
1nd1g0, интересно, а где у тебя вылетит новый метод Read
карма: 22

0
Ответов: 3889
Рейтинг: 362
#14: 2011-06-28 15:29:39 ЛС | профиль | цитата
nesco писал(а):
интересно, а где у тебя вылетит новый метод Read


WinExec -> LStrSetLength -> ReallocMem -> SysReallocMem -> SysGetMem -> TryHarder -> InsertFree (system) -> опять попытка записи в недопустимый адрес

Покопавшись в машинном коде приходим к выводу, что это - скомпилированная 118-я строка WinExec:

SetLength(pBuffer, Total);

Физически история проблемы такая же - менеджер памяти обращается к области памяти за пределами допустимого адресного пространства и благополучно улетает.
------------ Дoбавленo в 15.29:
Кстати, это объясняет, почему поведение разное на разных операционных системах и даже на одной. Менеджер памяти обращается к адресам с очень большим разбросом. Некоторые - действительно попадают в доступный ему сегмент данных и ошибки не происходит, туда попадают нужные данные и всё работает. Некоторые попадают в сегменты, доступные, но защищённые - происходит исключение по ошибке №204 самого паскаля. Некоторые обращения попадают на защищённые системой области памяти и вылетает дебаггер (если он у Вас стоит).

Вполне верю, что на некоторых системах с большим количеством оперативной памяти и современным ядром NT6.x , в котором улучшен менеджер памяти, может работать. Там ещё и механизмы многопоточности физически по-другому реализованы.
карма: 1

0
Разработчик
Ответов: 26170
Рейтинг: 2127
#15: 2011-06-28 15:50:41 ЛС | профиль | цитата
1nd1g0 писал(а):
Физически история проблемы такая же - менеджер памяти обращается к области памяти за пределами допустимого адресного пространства и благополучно улетает

А если проверить на другой схеме, которую я перезалил, то там происходит выброс.

P.S. Гы. А если попробовать переменную pBuffer сделать глобальной, а не выделять ей память при каждом обращении к оверлэпиду, интересно, где тогда вылетит
------------ Дoбавленo в 15.32:
1nd1g0 писал(а):
Некоторые - действительно попадают в доступный ему сегмент данных и ошибки не происходит, туда попадают нужные данные и всё работает. Некоторые попадают в сегменты, доступные, но защищённые - происходит исключение по ошибке №204 самого паскаля

А какого черта система сама по себе производит реалокэйт памяти куда попало, а не в досутпную область, это что, намек на то, что метод перекрытия глючный у ReadFile Совсем не радует
------------ Дoбавленo в 15.42:
Посмотрел более детально, у ReadFile нет метода перекрытия, к методу запуска цепляется новый поток с асинхронным методом Read, а в нем читаются Pipe от консольнго приложения. А сам ReadFile не имеет перекрытого метода. Похоже, что сам поток глючит с выделенной памтью
------------ Дoбавленo в 15.50:
Короче, надо pBuffer сделать глобальной для всего класса и посмотреть

К примеру, так



type
THIWinExec = class(TDebug)
private
pBuffer: string;
hProcess: THandle;
hPipeInputWrite: THandle;
...

А из метода Read не забыть убрать или поставить ремарку
карма: 22

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)