1

With Firemonkey 10.4.2 (same with 10.4.1) I have a lot of error like the one below :

External exception 1 At address: $0000007FF99E60D0

Call stack: libMyApp.so $00000074942D3B64 Grijjy.Errorreporting.TgoExceptionReporter.GlobalGetExceptionStackInfo(TExceptionRecord*)

  • 124 libMyApp.so $0000007493A42480 Sysutils.Exception.RaisingException(TExceptionRecord*) + 52 libMyApp.so $0000007493A6D5B4 Sysutils.RaiseExceptObject(TExceptionRecord*) + 64 libMyApp.so $0000007493A227D0 _RaiseAtExcept(TObject*, Pointer) + 64 libMyApp.so $0000007493A4164C Internal.Excutils.SignalConverter(NativeUInt, NativeUInt, NativeUInt) + 36 libMyApp.so $00000074942CE0BC Pebble.Thread.TPebbleThread_Execute_ActRec._0_Body() + 1328 libMyApp.so $00000074942CE0BC Pebble.Thread.TPebbleThread_Execute_ActRec._0_Body() + 1328

To load marker on a MapView I use a thread create with FreeOnTerminate set to False.

TPebbleThread = class(TThread)
strict private
  FMapView: TMapView;
  FListMarker: TListCustomMapMarker;
  FLatitude: Double;
  FLongitude: Double;
  FShowMapViewAtEnd: boolean;
  FImgList: TImageList;
  FIsTerminate: boolean;
  FForceShowAllPebble: boolean;
  FCheckDuplicate: boolean;
public
  constructor Create(aMapView: TMapView; aListMarker: TListCustomMapMarker; aLatitude, aLongitude: Double);
  destructor Destroy; override;
  procedure Execute; override;
end;

This thread contain some property.

TListCustomMapMarker = class(TObjectList<TCustomMapMarker>)
  // ...
end

TCustomMapMarker = class
strict private
  FMarker: TMapMarker; // record in FMX.Maps
  FId: integer;
  FCreated: string;
  FAdded: string;
  FUser: string;
  FKm: string;
  FComment: string;
  FOwner: string;
  FFixed: boolean;
public
  constructor Create;
  destructor Destroy; override;
  // property
end;

I surrounded the execute method with a try..except. I saw some errors that I fixed, but these exception didn't go in my except.

It's like the exception is raise before all (may be when I call it a 2nd time ?)

On my main form, I load the map with my thread :

procedure TfrmMain.LoadMapMarker;
begin
  if Assigned(FPebbleThread) then
  begin
    FPebbleThread.Terminate;
  end;

  FListMarker.RemoveMapMarker;

  FPebbleThread := TPebbleThread.Create(FListMarker, ...);
end;

The full thread method is below :

procedure TPebbleThread.Execute;
var
  Url            : string;
  i              : integer;
  HTTPResponse   : TToolHTTPResponse;
  Value          : TJSONValue;
  Ar             : TJSONArray;
  LatitudeDouble : Double;
  LongitudeDouble: Double;
  Latitude       : string;
  Longitude      : string;
  CustomMapMarker: TCustomMapMarker;
  Id             : integer;
  Param          : TMultipartFormData;
begin
  inherited;
  FIsTerminate := False;
  try
    Param := TMultipartFormData.Create;
    try
      Param.AddField('latitude',  FLatitude.ToString);
      Param.AddField('longitude', FLongitude.ToString);

      Param.AddField('filter', 'on');

      HTTPResponse := TToolHTTP.Post(CST_URL_WS_GET_PEBBLE, Param);
    finally
      FreeAndNil(Param);
    end;

    if HTTPResponse.Valid then
    begin
      try
        Value := TJSONObject.ParseJSONValue(HTTPResponse.Content);
        Ar := Value.FindValue('item') as TJSONArray;

        try
          if Assigned(Ar) then
          begin
            try
              i := 0;

              while (i <= Ar.Count - 1) and not Terminated do
              begin
                Id := Ar.Items[i].GetValue<integer>('id');

                if not FCheckDuplicate or
                   (FCheckDuplicate and not FListMarker.Exists(Id)) then
                begin
                  Latitude  := Ar.Items[i].GetValue<string>('latitude');
                  Longitude := Ar.Items[i].GetValue<string>('longitude');

                  LatitudeDouble  := TToolMath.StrToFloat(Latitude);
                  LongitudeDouble := TToolMath.StrToFloat(Longitude);

                  if (LatitudeDouble <> 0) and (LongitudeDouble <> 0) then
                  begin
                    CustomMapMarker := TCustomMapMarker.Create;
                    CustomMapMarker.Id        := Id;

                    TThread.Synchronize(nil,
                    procedure
                    var
                      Descr: TMapMarkerDescriptor;
                    begin
                      if not Terminated then
                      begin
                        Descr := TMapMarkerDescriptor.Create(TMapCoordinate.Create(LatitudeDouble, LongitudeDouble), '');
                        Descr.Snippet := CustomMapMarker.Id.ToString;
                        Descr.Icon := FImgList.Bitmap(TSizeF.Create(CST_IMG_SIZE, CST_IMG_SIZE), CST_IMG_MARKER_FACEBOOK)

                        CustomMapMarker.Marker := FMapView.AddMarker(Descr);
                        FListMarker.Add(CustomMapMarker);
                      end;
                    end);
                  end;
                end;
                i := i + 1;
              end;
            except
              on E: Exception do
                raise Exception.Create('[On loading] ' + E.Message);
            end;
          end;
        finally
          FreeAndNil(Value);

          if FShowMapViewAtEnd then
          begin
            TThread.Synchronize(nil,
            procedure
            begin
              FMapView.Visible := True;
            end);
          end;
        end;
      except
        on E: Exception do
          raise Exception.Create('[loading] ' + E.Message);
      end;
    end;
  finally
    FIsTerminate := True;
  end;
end;

I spent a lot of time to see what can cause these error but that didn't work. Did you see a mistake somewhere ? thanks

Bosshoss
  • 783
  • 6
  • 24
  • First, there is not enough code here to see what is your actual problem and propose solution. But, few things... it seems like you are accessing visual controls from the background thread which is not thread safe. Next, not all exceptions can be caught on LLVM based compilers (Android, iOS) see: https://stackoverflow.com/questions/52651931/why-the-exception-is-not-caught-by-the-try-except-end – Dalija Prasnikar Apr 26 '21 at 14:13
  • Thanks, I didn't see that. I added my full thread code – Bosshoss Apr 26 '21 at 14:27
  • Yu added full code (now, too much because not all this code is relevant for reproducing problem), but there are still things missing. Please read how to provide [mcve]. Also it is important to locate line where exception happens. We don't know what is TToolHTTP - is this call to static function, is your FImgList assigned and so on, if the issue is not related to retrieving online data, then remove that part and try using some fixed prepopulated data to examine the rest of the code. You need to do some debugging yourself to narrow down the issue. – Dalija Prasnikar Apr 27 '21 at 07:40
  • I know, but if I was able to do a MRE I wouldn't post here. I already remove lot of line in this thread before post it. TToolHTTP just do a HTTP call and return a Json from my API. All parameter are assigned, FImgList is a ImageList from a DataModule. I can't tell you where exception happens because that's come from my app users and I never reproduce it :( – Bosshoss Apr 27 '21 at 08:34
  • Well, in that case there is very little what we can do here. Exception is raised inside TPebbleThread_Execute_ActRec._0_Body() which means somewhere inside first Synchronize anonymous method. Because, some exceptions cannot be caught on Android, they will leak through your try...except blocks. Another question here is why are you catching and re-raising exceptions (just to add "On loading" or "loading" message seems like overkill) – Dalija Prasnikar Apr 27 '21 at 09:58
  • One thing that can possibly happen and this is also not part of the code presented here, is that exception can occur, on shutdown - in other words, your thread may be running while your GUI is already destroyed. – Dalija Prasnikar Apr 27 '21 at 10:00
  • I write more detail in my except (I remove it to post more clear code here), thats why I catch it and re-raise. Ok I will check that point, hope Embarcadero will fix it in news version – Bosshoss Apr 27 '21 at 10:25
  • I am not sure whether re-raising has issues, but that you can easily test yourself with quick test. Issue with leaking hardware exceptions (linked SO question) cannot be solved by Embarcadero because this is problem with LLVM backend not the Delphi compiler. – Dalija Prasnikar Apr 27 '21 at 11:14

1 Answers1

2

Ok, I would push a "FPebbleThread.WaitFor" in your frMain.LoadMapMarker, after the FPebbleThread.Terminate.

Such as this

if Assigned(FPebbleThread) then
begin
  FPebbleThread.Terminate;
  FPebbleThread.WaitFor;
end;

The TThread.Terminate method just set a boolean, your thread is certainly not propertly terminate when you create a new one.

Vincent
  • 21
  • 1
  • 3