Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.06.26;
Скачать: CL | DM;

Вниз

AV в ntdll.dll...?   Найти похожие ветки 

 
istok   (2011-03-16 22:46) [0]

есть такой код для записи в файл:


CS: SyncObjs.TCriticalSection;
....

procedure WriteLog(Str: string; AFileName: string);
var
 f: TextFile;
begin
 CS.Enter;
 try
   AssignFile(f, AFileName);
   try
     if FileExists(AFileName) then
       Append(f)
     else
       Rewrite(f);
     Writeln(f, Format("[%s](%d): %s", [DateTimeToStr(Now), GetCurrentThreadId, str]));
   finally
     CloseFile(f);
   end;  
 finally
   CS.Leave;
 end;
end;


при интенсивном использовании этого кода разными потоками иногда получаю вот это (eurekalog):

Access violation at address 00000000. Read of address 00000000.

---------------------------------------------------------------------------------------------------------------
|Address |Module        |Unit                |Class                    |Procedure/Method             |Line    |
---------------------------------------------------------------------------------------------------------------
|Running Thread: ID=10680; Priority=??; Class=                                                                |
|-------------------------------------------------------------------------------------------------------------|
|775E7760|ntdll.dll     |                    |                         |RtlLeaveCriticalSection      |        |
|775E6A22|ntdll.dll     |                    |                         |NtWaitForSingleObject        |        |
|775E7012|ntdll.dll     |                    |                         |KiUserExceptionDispatcher    |        |
|0053F1CA|wecmsg.exe    |WebFilterUnit.pas   |TWebFilter               |InStrings                    |2016[3] |
|0053F17C|wecmsg.exe    |WebFilterUnit.pas   |TWebFilter               |InStrings                    |2013[0] |
|0053F655|wecmsg.exe    |WebFilterUnit.pas   |TWebFilter               |CheckForBlockedUrl           |2131[53]|

Метод InStrings через цепочку событий (синхронизируются) в итоге вызывает WriteLog:

function TWebFilter.InStrings(AStr: string; AStrings: TStrings): Boolean;
var
 i: Integer;
begin
 Result := False;

 DoMessage("InStrings, AStr="+AStr+", AStrings.Text="+AStrings.Text);

procedure TWebFilter.DoMessage(AMessage: string; ADebugOnly: Boolean = True);
begin
 if Assigned(FOnMessage) then
   FOnMessage(Self, AMessage, ADebugOnly);
end;

procedure TWebFilterThread.DoOnThrdMessage(Sender: TObject;
 AMessage: string; ADebugOnly: Boolean = True);
begin
 DoSyncMessage(AMessage, ADebugOnly);
end;

procedure TWebFilterThread.DoSyncMessage(AMessage: string; ADebugOnly: Boolean = True);
begin
 FMessage := AMessage;
 FDebugOnly := ADebugOnly;
 Synchronize(DoMessage);
end;

procedure TWebFilterThread.DoMessage;
begin
 if Assigned(FOnThrdMessage) then
   FOnThrdMessage(Self, FMessage, FDebugOnly);
end;

procedure TThreadedWebFilter.DoOnThrdMessage(Sender: TObject;
 AMessage: string; ADebugOnly: Boolean = True);
begin
 if Assigned(FOnMessage) then
   FOnMessage(Sender, AMessage, ADebugOnly);
end;

procedure TweClientMessengerService.DoOnWebFilterMessage(Sender: TObject;
 AMessage: string; ADebugOnly: Boolean = True);
begin
 AddLog("WebFilter, DoOnMessage: "+AMessage, ADebugOnly);
end;

procedure TweClientMessengerService.AddLog(AStr: string; ADebugOnly: Boolean = True);
begin
 if FDebugMode then
 try
   WriteLog(AStr, FweFolders.dirCurrent + "weClientMessengerLog_DEBUG.txt");
 except
 end;
end;


я в нужном месте ищу баг? что может значить данный AV в ntdll.dll   RtlLeaveCriticalSection ? Критич. секция не срабатывает почему-то или дело в чем-то другом?


 
istok   (2011-03-16 22:47) [1]

забыл добавить: в итоге в выводимом файле после эксепшена иногда остаются незавершенные строки или вообще случайные символы попадают..


 
sniknik ©   (2011-03-16 22:58) [2]

> этого кода разными потоками
почитай в хелпе про DateTimeToStr


 
istok   (2011-03-16 23:04) [3]

я понимаю что она not thread-safe, но я ж критич секцию юзю. разве не спасает?


 
sniknik ©   (2011-03-16 23:22) [4]

> критич секцию
с основным потоком?

> разве не спасает?
ну как сказать, само по себе, без логики, это как спасательный круг дома, когда тонешь на море.


 
istok   (2011-03-16 23:30) [5]

почему ж с основным.., судя по логам и значению GetCurrentThreadId, этот код вызывают разные потоки... значит и enter\leave делается разными потоками. нет?


 
sniknik ©   (2011-03-16 23:57) [6]

да, да, пусть у тебя 10 спасательных кругов, и ты их дома красиво по стенкам периодически развешиваешь... к чему это на море?

> я понимаю что она not thread-safe
а понимаешь почему?


 
RWolf ©   (2011-03-16 23:59) [7]


> Метод InStrings через цепочку событий (синхронизируются)
> в итоге вызывает WriteLog:

но эврика-то указывает на эксепшен в InStrings, при чём тут WriteLog?


 
istok   (2011-03-17 00:07) [8]

в InStrings eureka указывает на строку


> DoMessage("InStrings, AStr="+AStr+", AStrings.Text="+AStrings.
> Text);


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

а без записи в лог (та же цепочка событий, только writelog не делается) эксепшен и не ловится.


 
RWolf ©   (2011-03-17 00:12) [9]


> я не понимаю, что тут криминального

AStrings.Text, видимо.


 
istok   (2011-03-17 00:57) [10]

хм.. логирование показывает что всё что касается класса TWebFilter, на который указывает eureka, идёт из одного потока..

а разные потоки пересекаются только в writelog, где и стоит cs...

можете подсказать, что есть RtlLeaveCriticalSection  в ntdll.dl  ? его как следствие вызывает моя критич. секция при leave или это могут быть еще какие-то не созданные мною cs ?


 
Германн ©   (2011-03-17 02:37) [11]


> istok   (17.03.11 00:57) [10]

Если Эврика лицензионная, рекомендую напрямую обратиться в суппорт Эврики. Помогут, чем смогут.


 
sniknik ©   (2011-03-17 08:07) [12]

> идёт из одного потока..
из основного? а изменения с ним ты синхронизируешь? особенно в случае с DateTimeToStr где его настройки для него (из за которых "not ...") меняются в недрах VCL... внезапно.

p.s. если это логер, то логичнее было бы вынести его самого/работу с файлом в поток, а не пытаться синхронизироваться со всеми. а данные на запись ему посылать в сообщении. ИМХО конечно.


 
Anatoly Podgoretsky ©   (2011-03-17 09:08) [13]

Ничего криминального, только аргумент равен NIL
Недавно был аналогичный вопрос, тоже предложили восспользоваться Еврикой или подобным, а на уточняющий вопрос, как это поможет в случае "Access violation at address 00000000. Read of address 00000000." благополучно умолчали.


 
han_malign   (2011-03-17 10:48) [14]


> аргумент равен NIL

if Assigned(FOn...) then FOn...(...);
- у автора делается честно, больше callback-ов там вроде не видать...
это к вопросу об:
> как это поможет в случае "Access violation at address 00000000

- раскрутка стека помогает(иногда) локализовать место, где надо искать вызов функции, в которой осуществляется выход за границу локальной(размещенной на стеке) структуры.
Причем 1-4 младших байта "at address" совпадает с тем, что за эту границу писалось...


 
sniknik ©   (2011-03-17 12:08) [15]

>> аргумент равен NIL

> if Assigned(FOn...) then FOn...(...);
> - у автора делается честно, больше callback-ов там вроде не видать...
это к вопросу об:
это не аргумент, это проверка метода обработчика, аргумент это FOn...(...); здесь.


 
sniknik ©   (2011-03-17 12:09) [16]

> FOn...(...здесь...);


 
istok   (2011-03-17 14:21) [17]

пока пришел к выводу что не синхронизировался DoMessage, он потом вызывает методы\события которые синхронятся через synchronize и естественно в writelog всё что идет по этому пути выдаёт один threadid

значит причина несинхрона где-то ДО этого..  

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

я уже запутсля в понимании того, что можно делать потокам без синхрона, а что нельзя...  vcl-то понятно что низя, но тут одни переменные, часто tstringlist..  причем локальные... есть tstringlist у одного потока, есть у другого.. они выводят их через domessage на печать, передавая параметром tstringlist.text, а синхрон идёт уже после этого вызова.. криминально?

но даже если tstringlist переменная есть глобальная, доступная всем потокам - _ЧИТАТЬ_ одновременно всем можно или синхронить надо??

stringlist безусловно непотокобезопасен при записи, но если речь о чтении, то как?


 
istok   (2011-03-17 14:36) [18]

кажется я всё понял..

там разных потоков быть и не должно было (на уровне видимости из domessage), а они есть из-за пары несинхроненных вызовов методов этого потока из других потоков... и получаются уже непонятные последствия, т.к. там много чего начинает юзится общего для нескольких потоков..


 
Anatoly Podgoretsky ©   (2011-03-17 14:41) [19]

> istok  (17.03.2011 14:21:17)  [17]

> stringlist безусловно непотокобезопасен при записи, но если речь о чтении,
> то как?

А как же тогда там записи оказались?


 
istok   (2011-03-17 14:49) [20]


> А как же тогда там записи оказались?


-если пишет в tstrings только один поток, а читают несколько.. то ок или нет?
(вопрос больше теоретический)

практическая часть свелась к следующему:

есть method1 в thread1 и  method2 в thread2.
насколько я вижу, если method1 (из-под thread1) вызывает method2, то method2 выполняется в контексте thread1.

как сделать так, чтобы method1 (из-под thread1) вызывал method2 таким образом, чтобы method2 выполнялся в контексте thread2  ?


 
Anatoly Podgoretsky ©   (2011-03-17 15:05) [21]

> istok  (17.03.2011 14:49:20)  [20]

Теоритичекий говоришь?
Пусть было "Мама мыла раму" и в некоторый момент раму заменили на папу. Вот
и разрушение.
Так что требуется синхронизация или ThreadList


 
sniknik ©   (2011-03-17 19:41) [22]

> -если пишет в tstrings только один поток, а читают несколько.. то ок или нет?
блин, прямо мучения латентного голубого, типа "ну один раз не п. это понятно, но вот если только с одним, любимым, это же не считается... ведь правда? ок, или нет?"

по справке того же DateTimeToStr (для которого "понятно, что not thread-safe") которая не безопасна, и только потому что основной поток, один!, в используемые ей данные что то пишет.
если бы это "не считалось", то весь VCL тут же стал бы потоко безопасным, наполовину, для чтения. что не так.

> как сделать так, чтобы method1 (из-под thread1) вызывал method2 таким образом, чтобы method2 выполнялся в контексте thread2  ?
никак, код всегда работает в контексте того потока в котором вызывается. но можно -
> а данные на запись ему посылать в сообщении. ИМХО конечно.


 
Дмитрий Белькевич   (2011-03-17 21:17) [23]

Закоменть подозрительный кусок - DateTimeToStr, либо еще что-то. Поможет - значит там проблему нужно искать. Нет - значит еще что-то.


 
Loginov Dmitry ©   (2011-03-17 23:19) [24]


> Критич. секция не срабатывает почему-то или дело в чем-то
> другом?


Критическая секция - самый примитивный объект синхронизации. Он не глючит. Естественно, критическая секция должна быть создана (проинициализирована) до использования. А вот если ее не проинициализировать, то можно нарваться на какие угодно проблемы :)

Насчет "потоконебезопасности" DateTimeToStr. Здесь подразумевается, что результат работы данной функции может оказаться неожиданным, т.к. переменная, определяющая формат перевода даты в строку является глобальной, а значит теоретически изменить ее может параллельно выполняющийся код в любой момент времени. Привести к AV она не может. Не так давно где-то это обсуждалось.


 
han_malign   (2011-03-18 14:01) [25]


> > FOn...(...здесь...);

- а at address 00000000 - здесь(...) - потому что это адрес инструкции - а не параметра, и даже не ссылки на экземпляр класса...

Такая ситуация может возникать только в двух случаях:
1. при параметризованном переходе (call [], jmp [])
2. (для x86) при выходе из процедуры(ret) с запоротой точкой возврата


 
sniknik ©   (2011-03-18 14:11) [26]

> и даже не ссылки на экземпляр класса...
> function TWebFilter.InStrings(AStr: string; AStrings: TStrings): Boolean;


 
han_malign   (2011-03-18 15:22) [27]


> > function TWebFilter.InStrings(AStr: string; AStrings: TStrings): Boolean;

program av;
{$APPTYPE CONSOLE}
uses Classes, SysUtils;
procedure _fail(sl: TStrings);
begin
  Writeln(sl.Text);
end;

begin
 try
  _fail(nil);
 except
 on E: Exception do Writeln(E.Message);
 end;
 sl:= TStrings.Create;
 try
  _fail(sl);
 except
 on E: Exception do Writeln(E.Message + " at " + IntToHex(Cardinal(ExceptAddr), 8));
 end;
 sl.Free;
end.

---------
Access violation at address 004126CB in module "av.exe". Read of address 00000000
Abstract Error at 0040AEEF

- что я делаю не так?

Если что - то(в отличие от плюсов) "в абстрактном VMT[]" лежит @_AbstractError, а не nil...


 
RWolf ©   (2011-03-18 15:26) [28]


>  [27]

переменная sl не объявлена.


 
han_malign   (2011-03-18 15:36) [29]


> sl не объявлена.

- сначала только nil отработал, а после отработки AbstractError - лень было все заново копировать... и инкрементальное обновление сбойнуло :))


 
sniknik ©   (2011-03-18 15:55) [30]

> - что я делаю не так?
теоретизируешь и вносишь сумятицу в абсолютно, кристально, ясную ситуацию - есть "дырка"? закрыть!

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

> "в абстрактном VMT[]" лежит @_AbstractError, а не nil...
а ты вообще понимаешь о чем речь? при чем тут абстрактный базовый класс? он всегда указывается, как подходящий для "передач потомков".
а после следует вызов типа InStrings(Form.Memo1.Lines); (Lines объявлен абстрактный ну надо же) у которого есть события, а передается в поток...
вот о чем речь, а не о том что там используется абстрактный, и значит будет абстракт еррор, класс. VCL не потоко-безопасно, все, четко и ясно, вопрос закрыт, и никакие манипуляции с цифрами этого не изменят.
хотите еще "потрещать" на эту тему? с автором. он похоже желает чтобы его переубедили, что все у него ок, менять ничего не надо, и это все винда виновата...


 
istok   (2011-03-18 16:26) [31]

вобщем я закрыл дырки в виде пары вызовов методов потока twebfilter другими потоками с помощью критич. секций и всё стало ок.

т.е. в методы типа twebfilter.InStrings реально входили несколько потоков без синхронизации.

а прелесть в том, что без логирования не юзается tstrings в паре мест и соответственно не возникает ошибки - оптимизация компиляции или что тут причина "невылета" ошибки мне не понять, да и не важно)

всем спасибо за помощь!


 
han_malign   (2011-03-18 16:51) [32]


> следует вызов типа InStrings(Form.Memo1.Lines);
> VCL не потоко-безопасно

- при чтении из неконсистентного композитного объекта, может возникнуть AV чтения - не разрушающее ни кучи, ни стека... При этом at address - ну никак не будет нулевым.

А говорил я - не `что "этого" от "этого" быть не может`, а что если верить Эврике, и в том случае, если повезло с адекватностью снимка стека - в методе CheckForBlockedUrl, или в каком то методе ниже по списку лога, надо искать вызов вложенной функции в которой разрушается стек...
Этим я всего лишь отвечал АПП - что Эврика в некоторых случаях может сузить область поиска "странных ошибок", если ума хватит...

DIXI



Страницы: 1 вся ветка

Текущий архив: 2011.06.26;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.014 c
2-1300637668
istok
2011-03-20 19:14
2011.06.26
enumerated types...


2-1300644733
inslave
2011-03-20 21:12
2011.06.26
многопоточность


15-1299965393
Юрий
2011-03-13 00:29
2011.06.26
С днем рождения ! 13 марта 2011 воскресенье


2-1300369713
irzyxa
2011-03-17 16:48
2011.06.26
Куда в файл можно записать свой идентификатор


15-1299958215
Fergo
2011-03-12 22:30
2011.06.26
Люди обясните что в этом коде не так???