TTask[n] EThreadNameException - ios

Experts, take the following code snippet below:
var
aAllTasks : Array [0..1] of ITask //global private var
Procedure SetImage();
begin
//..
//.. Get a URL of an image stored on a server
//..
aAllTasks[0] := TTask.Run(
Procedure
begin
// Download the Image and display the image
end);
aAllTasks[1] := TTask.Run(
Procedure
begin
// Get the rating of the image from a REST server
end);
end;
when the debugger hits
aAllTasks[1] := TTask.Run(...);
I get
First chance exception at $001A30B5. Exception class EThreadNameException with message ''. Process APPNAME (126391)
It throws the exception but it does not seem to crash the App
This only happens when debugging/running iOS apps
iOS 9.2
RS 10 Seattle (with Update 1)
PA server 17.0 (with hotfix.. V 8.0.1.52)
Xcode version 7.2 (7C68)
What would cause this and how would I fix it?

Your code calls, TThread.NameThreadForDebugging. That looks like this:
class procedure TThread.NameThreadForDebugging(AThreadName: string; AThreadID: TThreadID);
{$IF Defined(MSWINDOWS)}
.... // windows specific code removed
{$ELSE MSWINDOWS}
const
cExceptionMessage = 'Type=$1000,Name=%s,ThreadID=%d,Flags=0';
EMBDBKPRESENTNAME = 'EMB_DBK_PRESENT';
{$IF Defined(MACOS)}
OLDEMBDBKPRESENTNAME = 'EMB_MACOSX_DBK_PRESENT';
{$ENDIF}
begin
{$IF Defined(MACOS)}
if (getenv(EMBDBKPRESENTNAME) <> nil) or (getenv(OLDEMBDBKPRESENTNAME) <> nil) then
{$ELSEIF Defined(ANDROID)}
if (System.DebugHook <> 0) or (getenv(EMBDBKPRESENTNAME) <> nil) then
{$ELSE}
if (getenv(EMBDBKPRESENTNAME) <> nil) then
{$ENDIF}
begin
try
raise EThreadNameException.Create(
Format(cExceptionMessage, [AThreadName, AThreadID]));
except
end;
end;
end;
{$ENDIF !MSWINDOWS}
This function is called when you wish to give your thread a name. Now, thread objects do not have names. So when you give your thread a name, it is for debugging purposes only. The debugger keeps track of the names you provide, and associates them with thread IDs. Then when the debugger presents information about threads, it can look up the name from the ID and present that to you. But this is purely a debugger mechanism because the operating system does not support thread names.
So, how do you signal to the debugger that you wish to give a thread a name. Well, you throw a specific exception. The debugger is aware of the exception and gets the first chance to handle the exception. The debugger receives the name and the thread ID in the exception text and makes a note of that information.
Notice that the exception is swallowed immediately and so this does not interrupt the flow of the program.
So, it is normal for this exception to be raised, to be handled by the debugger, and not to impact on the behaviour of the program. What is odd is that the debugger is breaking on that exception. I would have expected that exception to be ignored by the debugger, by default.
An old QC report (QC#105310) for OSX describes exactly the behaviour that you are observing. That issue was closed and marked as fixed in XE7. Perhaps this issue has re-surfaced, or perhaps it was never fixed for the mobile platforms. I suggest that you submit a bug report to Quality Portal.

Related

Accessing TObject instance when it is locked by TMonitor.Enter in the calling thread

What will happen if a thread tries to access the same object locked by another thread? I know it can be handled by TMonitor.Wait(), but what if there is no handling codes to check if it is locked? Will there be an error?
In the example below, Thread1Process locks the object and Thread2Process attempts to assign a value to the object's property. Will the Thread2Process automatically wait before Thread1Process releases the lock to execute the next line var x: Integer := 1; or will it stop and throw an exception?
procedure Thread1Process(const AObject: TObjectDescendant);
begin
TMonitor.Enter(AObject);
try
// lengthy process here...
finally
TMonitor.Exit(AObject);
end;
end;
procedure Thread2Process(const AObject: TObjectDescendant);
begin
AObject.StringProperty := 'Any value';
var x: Integer := 1;
end;
We are using Delphi 11 Alexandria.
TMonitor is just a synchronization lock, nothing more. Much like TMutex, TSemaphore, etc.
It doesn't do anything to the object itself. If one thread decides to enter the lock, and a second thread doesn't, the second thread will not be blocked in any way, and no exception will be raised 1, but there is no guarantee to the stability of the object or its members. Race conditions occur due to lack of proper synchronization by all involved threads cooperating with each other.
1: unless the object itself decides to raise an exception, or a system exception is raised, like from accessing invalid memory, etc.
On a side note, your call to TMonitor.Enter() needs to be outside the try block, eg:
procedure Thread1Process(const AObject: TObjectDescendant);
begin
TMonitor.Enter(AObject);
try
// lengthy process here...
finally
TMonitor.Exit(AObject);
end;
end;

Calling TJSONUnMarshal.Unmarshal on a marshalled TStringlist causes memory corruption?

This q is to provide an MCVE to illustrate a problem uncovered by the answer to this earlier one of mine:
Unexpected failure of custom registered Reverter using TJSONUnMarshal
In my earlier q, the answer from #VirusTrinity fixed the problem I was initially having,
namely that the object obtained by the unmarshalling operation was incorrectly returned
with a Nil TStringlist field. However, the fix uncovered a new problem, which is that
on shutdown of the application, it generates a 0xC0000005 exception, access violation at
address 0x00000000 read of address 0x00000000. The code below shows this behaviour, generating
the same AV on shutdown, with the same cause.
The AV evidently occurs due to memory corruption during execution of PopulateFields(objFields, Obj, customizer); in function TJSONUnMarshal.CreateObject(JsonObj: TJSONObject): TObject in Data.DBXJSONReflect.
If you put a breakpoint where shown below in the code, add a watch on
TEncoding.FAnsiEncoding and then single-step through
AnObject:= jUnmarshal.Unmarshal(jValue);
you should find that the value in the FMaxCharSize changes from 1 to 5 (sometimes
in the previous q I got 7 instead of 5). This change seems to be symptomatic of
the memory corruption which apparently causes the AV on shutdown.
Update: To see where the AV occurs, place a breakpoint on the entry point to class procedure TEncoding.FreeEncodings. For me, the AV occurs when
FreeAndNil(FANSIEncoding);
is called.
Update #2: The point where TEncoding.FAnsiEncoding gets corrupted is when function TJSONUnMarshal.ClassTypeOf is called with the Field parameter having the value FDelimiter and executes the statement
fRtti := tRtti.GetField(Field);
The call to ClassTypeOf is from the statement
else if HasReverter(ComposeKey(ClassTypeOf(Data, FieldName),
FIELD_ANY)) then
at line 30222/3023 of procedure TJSONUnMarshal.PopulateFields
Could anyone confirm the problem and advise why it is occurring?
Code:
program MATest;
{$APPTYPE CONSOLE}
uses Classes, System.SysUtils, JSon, DBXJson, DBXJSONReflect;
procedure Test;
var
TL1,
TL2 : TStringlist;
AnObject : TObject;
jMarshal: TJSONMarshal;
jUnMarshal : TJSonUnMarshal;
jValue: TJSONValue;
begin
TL1 := TStringlist.Create;
TL1.Add('AAA');
try
jMarshal := TJSONMarshal.Create(TJSONConverter.Create);
jValue := jMarshal.Marshal(TL1);
Writeln(jValue.ToString);
jUnMarshal := TJSONUnMarshal.Create; // < Put breakpoint here and
// add watch of TEncoding.FAnsiEncoding in System.SysUtils
AnObject:= jUnMarshal.UnMarshal(jValue);
TL2 := TStringlist(AnObject);
Writeln(TL2.Text);
Readln;
finally
jValue.Free;
jMarshal.Free;
jUnMarshal.Free;
TL1.Free;
TL2.Free;
end;
end;
begin
try
Test;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

Exception when calling DLL in delphi?

I have a procedure to call a function named [main()] from a DLL , this is the Caller procedure :
procedure call_dll(path:string);
var
lib: HMODULE;
mainfn: procedure(); stdcall;
begin
if FileExists(path) then
begin
try
lib := LoadLibrary(PAnsiChar(path));
Win32Check(lib <> 0);
try
#mainfn := GetProcAddress(lib, 'main');
Win32Check(Assigned(mainfn));
mainfn();
finally
FreeLibrary(lib);
end;
except
end;
end;
end;
Until yet every thing is working fine , I mean after writing the correct path of the DLL everything work without a problem but if I write a wrong path (other file path) in the path parameter it show me a popup error that this is is not a Win32 DLL but I don't want to bother the user with this type of errors , so I need a function to check the DLL and if it's not then it will automatically ask for another file again without showing the popup error ?
It is your code that is raising the exception. Your code makes an explicit choice to handle errors by raising exceptions. The exception is raised by your code here:
Win32Check(lib <> 0);
If you don't want to raise an exception, don't use Win32Check. Instead check the value of lib and handle any errors by whatever means you see fit.
The same issue is present for your other use of Win32Check.
Of course you are swallowing all exceptions with your catch all exception handler. A catch all exception handler is usually a bad idea. I don't understand why you have included that. I think you should remove it.
So if you are seeing dialogs when running outside the debugger it follows that the system is producing the dialogs. You should be disabling the system's error message dialogs by calling SetErrorMode on startup passing SEM_FAILCRITICALERRORS.
var
Mode: DWORD;
....
Mode := SetErrorMode(SEM_FAILCRITICALERRORS);
SetErrorMode(Mode or SEM_FAILCRITICALERRORS);
The somewhat clunky double call is explained here: http://blogs.msdn.com/b/oldnewthing/archive/2004/07/27/198410.aspx

Detect running under AQTime? Avoid crashing debugging code

I usePerformance Profiler in AQTime. Trying to run it under IDE (using Embarcadero RAD Studio XE). Inspected project crashes on such code:
// Setting a Thread Name (Unmanaged):
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx
procedure _NameThreadForDebugging(const ATID: Cardinal; const AThreadName: String);
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PAnsiChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
var
ThreadNameInfo: TThreadNameInfo;
ThreadName: AnsiString;
begin
// Applicable only for debugged applications
if IsDebuggerPresent then
begin
FillChar(ThreadNameInfo, SizeOf(ThreadNameInfo), 0);
ThreadName := AnsiString(AThreadName);
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := PAnsiChar(ThreadName);
ThreadNameInfo.FThreadID := ATID;
try
RaiseException(cSetThreadNameExcep, 0, SizeOf(ThreadNameInfo) div SizeOf(LongWord), #ThreadNameInfo);
except
end;
Finalize(ThreadName);
end;
end;
It works fine when run outside of IDE (in which case the routine will exit without doing anything), or when run under usual IDE debugger (in which case the routine will raise exception, which will be handled by IDE's debugger).
However, when run under AQTime - the routine will crash right at call to kernel32.RaiseException routine (APPCRASH C00001A5 somewhere inside kernel32). I have confirmed this by putting MessageBoxes around this call (try/except block).
Apparently, IsDebuggerPresent is True when run under AQTime, but exception is not properly handled.
Question: how can I detect and avoid this? How can I check if code is executed under AQTime?
AQTime is 8.22.
You can check the following environment variables that are passed to the profiled process by default: AQTIME_DEBUGGER_PRESENT, AQTIME_SESSION_ID and AQTIME_VERSION.
Note: exact variables seems to depend on profiler used (or AQTime version?) - in my case only AQTIME_SESSION_ID and AQTIME_VERSION are present.

Access violation when open the teechart form at the second time

We're migrating our XE projects to XE5, however, we encountered the access violation exception about teechart during the test.
I've created a test application to recreate the issue. With the test app, it works fine when open the first teechart form but will get the access violation exception when open it second time or open a new form.
Please refer to the attached test app from the following QC (embarcadero).
http://qc.embarcadero.com/wc/qcmain.aspx?d=122729
When debug it with DCUs. The exception happened when notifying TDBChart's OnStateChange event.
procedure TDataSet.DataEvent(Event: TDataEvent; Info: NativeInt);
begin
...
if NotifyDataSources then
begin
for I := 0 to FDataSources.Count - 1 do
FDataSources[I].DataEvent(Event, Info); // <<---- Access Violation
if FDesigner <> nil then FDesigner.DataEvent(Event, Info);
end;
end;
As David Berneda said at Quality Central:
Its related to using an internal TObjectList generic collection inside
DBChart. The code has been improved so the error is fixed now (a new
code takes care of destroying the ObjectList items correctly).
As a workaround, you can add this code at your form's OnClose event:
type
TChartAccess=class(TDBChart);
procedure TOutcomesGraphFm.bbtnCloseClick(Sender: TObject);
begin
TChartAccess(dbcBar).RemovedDataSource(bsTestScores,bsTestScores.DataSource);
Close;
end;

Resources