Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Die Delphi-IDE (https://www.delphipraxis.net/62-die-delphi-ide/)
-   -   IDE: Compiler Einstellung für nicht initialisierte Variablen (https://www.delphipraxis.net/208721-ide-compiler-einstellung-fuer-nicht-initialisierte-variablen.html)

Athris 10. Sep 2021 08:52

IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Guten Morgen zusammen,

wir haben lange Zeit Delphi XE2 für die Kompilierung von verschiedenen Projekten genutzt.
Vor Kurzem benutzen wir nun parallel Delphi 10.4 und migrieren Stück für Stück unsere Projekte auf die neue IDE und von 32bit auf 64bit.

Hierbei ist uns nun etwas seltsames aufgefallen. Zuerst einmal einen Auszug aus dem Quellcode:
Delphi-Quellcode:
procedure TfrmMain.OnExitEdit;
var
  txtOrt, txtPLZ, txtLand, txtStrasse, txtBundesland: TEdit;
  strCheck: String;
begin
  if (Sender=nil) or (not (Sender is TEdit)) then exit;
  txtStrasse := nil;
  txtBundesland := nil;
  try
    //...
    //Nicht relevanter Quellcode entfernt
    //...
    else if pos( 'LAND', TEdit(Sender).Name)>0 then begin
      txtLAND := TEdit( Sender);
      txtLand.Text := CheckLandIso3( Databasename, txtLand.Text);
    end
    else begin
      exit;
    end;
  except
    on E:Exception do begin
      ShowMessage( E.Message);
      exit;
    end;
  end;
  //Hier tritt die Zugriffsverletzung unter 10.4 auf, während diese bei Delphi XE2 keine Zugriffsverletzung auftritt
  strCheck := GetGeoCheckAdressString( txtLand.Text, txtPLZ.Text, txtOrt.Text, txtStrasse.Text);
Delphi-Quellcode:
function GetGeoCheckAdressString( const vstrLand, vstrPLZ, vstrOrt, vstrStrasse: String): String;
begin
  Result := strSimple( vstrLand+vstrPLZ+vstrOrt+vstrStrasse);
end;

Die Funktion liefert unter Delphi 10.4 eine Zugriffsverletzung (was in unseren Augen korrekt ist, da die Variable gar nicht initiiert ist).
Unter Delphi XE2 kommt es aber zu keiner Zugriffsverletzung.

Nun sind wir etwas ratlos warum dies so ist. Gibt es eventuell eine Compiler Einstellung die solch ein Verhalten steuert?

himitsu 10. Sep 2021 09:43

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Erstmal sollte dir der Compiler schon länger eine Fehlermeldung geben, dass Variablen nicht initialisiert seien. (die zwei, welche vorher nicht auf NIL gesetzt wurden)
Somit ist ihr Wert per se zufällig, jenachdem was grade auf dem Stack vorher dort rumlag.

Aber auch NIL hilft nicht viel, da du ja auf Eigenschaften der Objekt-Instanz zugreifen willst.

Und dank dem EXIT können da unten somit alle Variablen sowohl einen Wert, NIL oder "sonstwas" drin haben. (man sieht nicht alles an Code, aber NIL ist vielleicht abgefangen, also somit eigentlich garnicht nötig)


Es ginge auch so:
Oben auf ALLES auf NIL setzen
und Unten darauf prüfen :!:
Oder besser einfach direkt in der Funktion.
Und das Exit-gehopse auch weg.

Hier würde auch was angezeigt, wenn nur ein Edit nicht gefunden wurde.
Delphi-Quellcode:
strCheck := GetGeoCheckAdressString(txtLand, txtPLZ, txtOrt, txtStrasse);

...

function GetGeoCheckAdressString(vtxtLand, vtxtPLZ, vtxtOrt, vtxtStrasse: TEdit): String;
begin
  Result := '';
  if Assigned(vtxtLand) then Result := Result + vtxtLand.Text; // wirklich ohne sowas wie z.B. ein ' ' dazwischen?
  if Assigned(vtxtPLZ) then Result := Result + vtxtPLZ.Text;
  if Assigned(vtxtOrt) then Result := Result + vtxtOrt.Text;
  if Assigned(vtxtStrasse) then Result := Result + vtxtStrasse.Text;
  Result := strSimple(Result);
end;
Nja, ohne das sinnlose Try-Except wird die Behandlung auch gleich viel Einfacher.
* entweder oben :=nil oder unten mit Exit raus -> Beides ist eigentlich nicht nötig, da entweder zugewiesen oder raus



PS:

Statt Pos<>0 ist Delphi-Referenz durchsuchenContainsStr (Delphi-Referenz durchsuchenContainsText) besser lesbar/verstehbar.
Steht "LAND" wirdklich irgendwo im String, oder meinst nicht eher sowas wie Delphi-Referenz durchsuchenStartsStr oder EndsStr? (bzw. StartsText oder EndsText)

Außerdem ist ShowMessage als "Fehlermeldung" nicht nur grauenhaft anzusehn,
sondern auch später extrem unproduktiv, wenn man mal ein richtiges Error-Management nuzten wöllte.
> Hier am Einfachsten diesen Try-Except-"Mist" weglassen.

Athris 10. Sep 2021 10:04

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Der Quellcode ist tatsächlich sehr alt (bestimmt über 15 Jahre). Das die Qualität des Codes eher mangelhaft ist, ist mir bewusst :-D

Die Frage ist nur warum XE2 niemals eine Zugriffsverletzung anzeigt (ist halt nie aufgefallen) und Delphi 10.4 immer eine Zugriffsverletzung anzeigt.

jaenicke 10. Sep 2021 10:09

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Zitat:

Zitat von Athris (Beitrag 1494448)
Die Frage ist nur warum XE2 niemals eine Zugriffsverletzung anzeigt (ist halt nie aufgefallen) und Delphi 10.4 immer eine Zugriffsverletzung anzeigt.

Das ist eben Zufall. Da steht nun zufällig etwas im Speicher, was beim Zugriff eine nicht zugreifbare Adresse ist. Du hattest vorher schlicht Glück, dass in der Variablen ein Wert stand, von dem aus eine Adresse berechnet werden konnte, an der ein Zugriff möglich war. Und dass an der Stelle dann etwas war, das man in dem String nicht sehen konnte / nicht bemerkt wurde.

Wichtig ist vor allem, dass du keine Compilermeldungen (Variable nicht initialisiert, ...) ignorierst, wenn du die Anwendung erzeugst. Damit hast du schon viele mögliche Fehlerquellen vermieden.

himitsu 10. Sep 2021 10:11

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Es kommt drauf an, was da im Speicher/Stack steht.

Wenn da irgendwas stand, was als Pointer interpregiert und mit einem kleinen Offset versehen (zu FHandle) auf reservierten Speicher zeigt, dann kann das als HWND für WM_GETTEXT genommen werden.
Selbst wenn dieses "HWND" ungültig ist, würde es keinen Fehler geben, da Delphi davon das Result/GetLastError nicht auswertet und somit nur einen Leertext liefert.

Athris 10. Sep 2021 10:24

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Danke für eure Antworten, doch bleibe ich etwas skeptisch bei der Antwort "Es ist zufall".

Das kann kein Zufall sein. Der Programmabschnitt ist jahrelang bei über 150 Kunden im Einsatz gewesen. Auch bei uns selbst wurde der Abschnitt diverse mal aufgerufen und es kam NIE zu einer Zugriffsverletzung.

Beim neuen Delphi 10.4 kommt die Zugriffsverletzung jedes mal. Immer. Das kann doch kein Zufall sein.

Oder hat es etwas damit zu tun das wir bei XE2 immer nur in 32 bit kompiliert haben und nun beim 10.4 in 64bit kompilieren?

himitsu 10. Sep 2021 10:29

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Für lokale Variablen und Result wird Speicher nicht initialisiert. (Ausnahme sind gemanagte Typen wie String oder Interface, wo Delphi von sich aus das Speichermanagement sicherstellen muß)

Sie haben also den Wert, welcher ein vorhergehender Funktionsaufruf dort auf dem Stack hinterlassen hatte.


Es "kann" immer der selbe Wert sein, wenn die Aufrufe in gleicher Reihenfolge sind, aber es muß nicht und somit ist der Wert "unbestimmt", also zufällig.
Und wenn ein neuer Compiler anderen Code erzeugt oder Variablen anders im Speicher ablegt, dann ist es nunmal plötzlich anders.

Athris 10. Sep 2021 10:32

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Mit der Antwort kann ich leben, vielen Dank!

jaenicke 10. Sep 2021 10:46

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Zitat:

Zitat von Athris (Beitrag 1494454)
Oder hat es etwas damit zu tun das wir bei XE2 immer nur in 32 bit kompiliert haben und nun beim 10.4 in 64bit kompilieren?

Da gibt es diverse Unterschiede. Einer davon, der für die Exceptionbehandlung wichtig ist:
Bei 32-Bit Programmen ist der Stackframe nicht fest. Deshalb ist es nicht so einfach möglich, nach einem Fehler einen sauberen Stacktrace aufzubauen.
Bei 64-Bit Programmen gibt es dafür eindeutige Vorgaben, so dass man in der Regel auch zuverlässige Stacktraces bekommt.

Der schöne Günther 10. Sep 2021 10:48

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Ich kann nichts mehr hinzufügen, genauso wie erklärt ist es.

Ich kann nur aus eigener Erfahrung berichten dass wir exakt den Fall auch hatten- Eine alte, nicht mehr gewartete Delphi-DLL mit so vielen Warnmeldungen über nicht initialisierte Variablen dass da auch keiner mehr geschaut hat. Lief viele Jahre lang.

Als sie eines Tages durch einen neueren Delphi-Compiler gejagt wurde gingen vereinzelte Dinge nicht mehr, keiner wusste weshalb. Lösung war exakt das gleiche: Eine nicht initialisierte Variable führte zu einer Zugriffsverletzung, und früher hat es bei einem älteren Compiler grade so gepasst dass nichts in sich zusammenbrach...

himitsu 10. Sep 2021 10:54

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Jo, 64 Bit ist immer mit StackFrames und es gibt auch nur noch eine Calling-Convension (sieht witziger Weise fast wie die von Delphi aus :stupid:),

aber es macht die Sache mit dem Stack viel einfacher.


Und zusätzlich seit 'ner kurzen Weile auch direkt eine WinAPI, zum lesen des Stacks und der Debuginfos.
Nur blöd, dass Delphi seine eigenen Debuginfos hat und man nicht aktivieren kann, dass man auch die "normalen" mit im Programm einkompiliert haben möchte.

jaenicke 10. Sep 2021 11:07

AW: IDE: Compiler Einstellung für nicht initialisierte Variablen
 
Zitat:

Zitat von himitsu (Beitrag 1494464)
Nur blöd, dass Delphi seine eigenen Debuginfos hat und man nicht aktivieren kann, dass man auch die "normalen" mit im Programm einkompiliert haben möchte.

Das kann man ja im Post Build Ereignis korrigieren. Aber ja: Ich fände es auch viel sinnvoller, wenn Delphi dies als Option mitbringen würde.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:47 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz