Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2011.06.26;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.008 c
2-1300783231
novichek
2011-03-22 11:40
2011.06.26
EXISTS или IN


15-1299765057
Leon-Z
2011-03-10 16:50
2011.06.26
Алгоритмы.


3-1261134567
pavel_guzhanov
2009-12-18 14:09
2011.06.26
Удаление записей в access


15-1294522629
двп
2011-01-09 00:37
2011.06.26
Система удаленного администрирования, потестить


2-1300254324
Andrey_1
2011-03-16 08:45
2011.06.26
DbGrid-ячейка в две строки





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский