SIGSEGV bei String-Zuweisung

Für Fragen rund um die Ide und zum Debugger
Antworten
HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Hallo,

mein Problem ist folgendes:

Ich bekomme eine Zugriffsverletzung (SIGSEGV) bei der Zuweisung eines Leerstrings auf eine Stringvariable (finde ich schon sehr merkwürdig).

Code: Alles auswählen

inherited create;
FRaiseExcept := false;
FHandle := INVALID_HANDLE_VALUE;
FDevice := ''; // <--- Zugriffsverletzung
FComNr:= PortIsClosed;
Das Lazarus-Hint (s. Anhang) zeigt mir beim Debuggen die Meldung an, dass die Adresse der Variablen außerhalb des Speicherbereichs liegt. Ich habe mal die Adresse als überwachten Ausdruck gesetzt, erhalte dabei aber eine völlig andere, meiner Meinung gültige, Adresse für die Variable FDevice.

Ich vermute deshalb, dass irgendwas mit dem GDB nicht richtig ist. Was meint ihr?

Meine Konfiguration ist:
  • Windows 7 Professional (x64)
  • Lazarus 0.9.30.4RC3 (win32)
  • FPC 2.6.0
Dateianhänge
Screenshot
Screenshot

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: SIGSEGV bei String-Zuweisung

Beitrag von theo »

Das kann fast nicht sein. Ich denke das ist eine falsche Fährte und das Problem liegt woanders. Das sehen wir hier aber nicht.

HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Ich habe jetzt nochmal einen Screenshot vom Aufrufstack und vom Assemblerauszug zum Exception-Zeitpunkt gemacht.

Die Funktion fpc_ansistr_decr_ref kommt mir an der Stelle auch irgendwie spanisch vor.


Kann ich der Stringvariable nicht auch auf alternativem Weg den Wert zuweisen?
Zum Beispiel so:

Code: Alles auswählen

String(@FDevice) := ''
Dateianhänge
Aufrufstack und Assembler
Aufrufstack und Assembler
"There are 10 kinds of human. Those who understand the binary system and those who don't."

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: SIGSEGV bei String-Zuweisung

Beitrag von theo »

Nee, ich sagte falsche Fährte. Überleg nicht, warum du den leeren String nicht dem String-Feld zuweisen kannst, dort liegt das Problem höchstwahrscheinlich nicht, sondern zeige deinen Code.

HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Habe mal alle relevanten Quelltexte in eine zip-Datei zusammengefasst.
Ich benutze die freie Komponente SynaSer (zur Kommunikation mit einem Gerät am seriellen Anschluss). Deren Quelltextordner habe ich auch mit reingepackt, denn die Exception bekomme ich ja im Create der Klasse TBlockSerial.
Möglicherweise habe ich ja einen Compilerschalter falsch gesetzt oder so.
Schonmal vielen Dank für die Mühe.
Dateianhänge
Quelltext.zip
(59.55 KiB) 77-mal heruntergeladen
"There are 10 kinds of human. Those who understand the binary system and those who don't."

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: SIGSEGV bei String-Zuweisung

Beitrag von theo »

HOffen hat geschrieben: Möglicherweise habe ich ja einen Compilerschalter falsch gesetzt oder so.
Davon sehe ich natürlich nicht viel.

Egal, ich hab's mal auf 64 bit Linux getestet. Dein Synaser hat bei mir aber nicht kompiliert.
So habe ich das von SVN benutzt. http://synalist.svn.sourceforge.net/vie ... z?view=tar" onclick="window.open(this.href);return false;

Das kompiliert und überlebt das Create ohne Absturz auf Lazarus 0.9.31 r35593M FPC 2.6.0 x86_64-linux-gtk 2

HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Hast du das Package installiert oder nur den Quellcode genommen? Ersteres schien mir und Lazarus unnötig, ist ja keine visuelle Komponente.

Jedenfalls bleibt der Fehler bei mir der gleiche: SIGSEGV bei Variable FDevice. :?

In Bezug auf die Compilerschalter meinte ich eigentlich die Direktiven im Quellcode, ein bisschen missverständlich ausgedrückt.

Macht es Sinn, eine andere Lazarus-Version zu installieren?
Momentan arbeite ich ja mit dem RC3 der 0.9.30.4. Ein Update auf die Final wird vermutlich nicht viel bringen.
"There are 10 kinds of human. Those who understand the binary system and those who don't."

Benutzeravatar
theo
Beiträge: 10859
Registriert: Mo 11. Sep 2006, 19:01

Re: SIGSEGV bei String-Zuweisung

Beitrag von theo »

HOffen hat geschrieben:Hast du das Package installiert oder nur den Quellcode genommen? Ersteres schien mir und Lazarus unnötig, ist ja keine visuelle Komponente.

Ich habe einfach die Package Abhängigkeit dem Projekt hinzugefügt. Das Package muss man ja nur einmal öffnen, damit es im Projektinspektor zur Verfügung steht. IDE kompilieren ist nicht nötig.

HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Objekte der Klasse TBlockSerial kann ich problemlos erzeugen. Also muss der Fehler ja eigentlich irgendwo in meiner davon abgeleiteten Klasse TRikaConnection liegen. Ich kann in meinem Quelltext aber keine Auffälligkeit entdecken.

Code: Alles auswählen

unit mRikaFunctions;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils,
{$IFNDEF SOME_LIB}
  Dialogs,
{$ENDIF}
  synaser,
  mRikaTypesAndConsts;
 
type
  TRikaConnection = class(TBlockSerial)
  private
    FLoggedOn: Boolean;
    FVersion: TRikaVersion;
    function IsDataAvailable: Boolean;
    function LogOn(const AQueryMode: Byte): Boolean;
    function LogOff: Boolean;
    procedure SetVersion(Value: String);
    function GetVersionString: String;
  public
    constructor Create(const AComPort, ABaud: SmallInt);
    destructor Destroy; override;
    function RecieveData: String;
    function RecieveDataSet: TRikaDataSet;
    property Version: TRikaVersion read FVersion {write SetVersion};
    property VersionString: String read GetVersionString;
  end;
 
const
  SleepDelay = 250;
 
 
implementation
 
constructor TRikaConnection.Create(const AComPort, ABaud: SmallInt);
begin
  inherited Create;
  Connect('COM' + IntToStr(AComPort));
  Config(ABaud, 8, 'N', SB1, False, False);
end;
 
destructor TRikaConnection.Destroy;
begin
  if FLoggedOn then
    LogOff;
  inherited Destroy;
end;
 
function TRikaConnection.IsDataAvailable: Boolean;
var
  Answer: Byte;
begin
  Result := False; // initialisieren
  SendByte(SYN);
  //Sleep(SleepDelay);
  Answer := RecvByte(GlobalTimeOut);
{$IFNDEF SOME_LIB}
  if LastError > 0 then ShowMessage(LastErrorDesc);
{$ENDIF}
  if Answer = SOH then
     Result := True;
end;
 
function TRikaConnection.LogOn(const AQueryMode: Byte): Boolean;
var
  LogOnAnswer: String;
begin
  if FLoggedOn then exit;
  Result := False; // initialisieren
  SendByte(AQueryMode);
  //Sleep(SleepDelay);
  LogOnAnswer := RecvPacket(GlobalTimeOut);
  SetVersion(LogOnAnswer);
  if LastError = sOK then
  begin
    FLoggedOn := True;
    Result    := True;
  end;
end;
 
function TRikaConnection.LogOff: Boolean;
begin
  if not FLoggedOn then exit;
  Result := False; // initialisieren
  SendByte(DISCONNECT);
  if ((LastError = sOK) and (RecvByte(GlobalTimeOut) = NUL)) then
  begin
    FLoggedOn := False;
    Result    := True;
  end;
end;
 
procedure TRikaConnection.SetVersion(Value: String);
begin
  if (Length(Value) < 3) then
  begin
    FVersion.MajorVersion := -1;
    FVersion.MinorVersion := -1;
    exit;
  end;
  FVersion.MajorVersion := StrToIntDef(Value[1],-1);
  FVersion.MinorVersion := StrToIntDef(Value[2]+Value[3],-1);
end;
 
function TRikaConnection.GetVersionString: String;
begin
  Result := 'Rika v' + IntToStr(Version.MajorVersion) + '.' + IntToStr(Version.MinorVersion);
end;
 
function TRikaConnection.RecieveData: String;
var
  DataString: String;
begin
  LogOn(CON_TOTAL);
  try
    if IsDataAvailable then
    begin
      try
        DataString := RecvTerminated(GlobalTimeOut, Char(EOT));
      finally
        SendByte(FF);
      end;
      Result := Result + DataString;
    end
    else
      Result := Result + '#NODATA';
  finally
    LogOff;
  end;
end;
 
function TRikaConnection.RecieveDataSet: TRikaDataSet;
var
  i, k: Integer;
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  try
    StringList.Text := RecieveData;
    if not (StringList.Text = '') then
    begin
      with Result do
      begin
        RikaSerialNumber := StrToIntDef(StringList.Strings[0], -1);
        RikaBusAddress   := StrToIntDef(StringList.Strings[1], -1);
        ManualCode       := StrToIntDef(StringList.Strings[2], -1);
        TargetIdent      :=             StringList.Strings[3];
        DivisorFactor    := StrToIntDef(StringList.Strings[4], -1);
        HitQuantity      := StrToIntDef(StringList.Strings[5], -1);
        SetLength(Hits, HitQuantity);
        k := 6;
        for i := 0 to HitQuantity - 1 do
        begin
          with Hits[i] do
          begin
            Points  := StrToIntDef(StringList.Strings[k],   -1);
            Divisor := StrToIntDef(StringList.Strings[k+1], -1);
            Divisor := StrToIntDef(StringList.Strings[k+2], -1);
            Divisor := StrToIntDef(StringList.Strings[k+3], -1);
            Inc(k, 4);
          end;
        end;
      end;
    end;
  finally
    FreeAndNil(StringList);
  end;
end;
 
end.

martin_frb
Beiträge: 586
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von martin_frb »

1) Benutzt du Optimization beim compilieren? -O2 ?
Der Debugger kann nur korrekt anzeigen mit entweder -O0 oder -O1

2) Ist irgendwo ein spezieller Memory manager?


Der Fehler kann (wenn die Werte stimmen) entweder sein:
- Das Memory fuer das Object wurde nicht mit 0x00 initialisiert, daher hat der String vor der Zuweisung einen ungültigen Wert, und das führt zum Crash)
Das ist extrem unwahrscheinlich.

- Irgend ein anderer Code schreibt in das Memory des String. Selber Effekt wie oben.

Welchen Wert hat der String, bevor "inherited" ist called?

HOffen
Beiträge: 16
Registriert: Do 15. Mär 2012, 09:19
OS, Lazarus, FPC: Win7 (L 0.9.30.4RC3 FPC 2.6.0)
CPU-Target: 32Bit

Re: SIGSEGV bei String-Zuweisung

Beitrag von HOffen »

Ich kann leider immer noch nicht sagen, woran es gelegen hat, aber es funktioniert jetzt wieder alles.

Ich habe mich schlussendlich dazu durch gerungen, ein neues Projekt anzulegen. Darin funktioniert das Erzeugen meines Klassenobjekts einwandfrei.
"There are 10 kinds of human. Those who understand the binary system and those who don't."

Antworten