[gelöst] Bug in WideCharToString

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
Antworten
Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

[gelöst] Bug in WideCharToString

Beitrag von Michl »

Hat mich jetzt über 4 Stunden fast in den Wahnsinn getrieben, bis ich endlich den Fehler eindeutig isolieren und ein Minimalbsp. erstellen konnte:

Getestet unter Lazarus 1.0.10 und 1.1, jeweils Win32: Test1 funktioniert, Test2 nicht!!! Unterschied sind 3 nicht gesetzte Integer-Variablen:

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Forms, StdCtrls, HTMLDefs, StrUtils;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure Test1;  //funktioniert
var
  x,y,z,a:integer;
  s,sd:widestring;
  wc:widechar;
begin
  s:='Uuml';
  if ResolveHTMLEntityReference(s,wc) then
    Form1.Caption:=UTF8Encode(WideCharToString(@wc));
end;
 
procedure Test2;  //funktioniert nicht
var
//  x,y,z,a:integer;    //Das ist der Unterschied, Kommentar entfernen und Procedure funktioniert!
  s,sd:widestring;
  wc:widechar;
begin
  s:='Uuml';
  if ResolveHTMLEntityReference(s,wc) then
    Form1.Caption:=UTF8Encode(WideCharToString(@wc));
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Test1;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  Test2;
end;
 
end.
Ich bitte um Bestätigung oder Workaround. Danke!
Zuletzt geändert von Michl am So 18. Aug 2013, 10:10, insgesamt 1-mal geändert.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Antrepolit
Beiträge: 340
Registriert: Di 12. Sep 2006, 08:57
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Bug in WideCharToString

Beitrag von Antrepolit »

Und was soll es machen und was funktioniert nicht? DU hast ne TStringList, die du nicht brauchst, noch dazu als globale Variable. Du castest irgendwas von String nach WideChar um dann wieder auf UTF8 zu encodieren für den Form-Titel - wozu? Wenn ich das unter 64 Bit Windows teste funktioniert kein Button wie er (vermutlich) soll. Aber warum auch, wenn man Pointer verwendet und nicht weiß, was die tun. Was hast du da überhaupt vor?

Von einem Bug in einer Funktion kann keine Rede sein. Ich sehe da keinen sinnvollen Quellcode.
Grüße, Antrepolit

care only if your os is really burning

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Bug in WideCharToString

Beitrag von Michl »

Habe soeben das Projekt nochmals geändert. Da der Fehler erst bei beiden Proceduren auftrat, als ich die Stringlist entfernt hatte. Jetzt habe ich noch eine Integer-Variable dazu genommen und es ist der Fehler reproduzierbar!

Button1.Klick -> Caption="Ü" -> Korrekt !!!
Button2.Klick -> Caption="Ü???S???(FF????FGNBH???" -> Falsch !!!

Das ist ein Minimalbsp und hat als solches keinen Sinn!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Bug in WideCharToString

Beitrag von Socke »

Michl hat geschrieben:Hat mich jetzt über 4 Stunden fast in den Wahnsinn getrieben, bis ich endlich den Fehler eindeutig isolieren und ein Minimalbsp.
Gehören die String-Listen zum Minimalbeispiel?
Michl hat geschrieben:Ich bitte um Bestätigung oder Workaround. Danke!
Angenommen, dein Quelltext ist in UTF-8 kodiert. Falls das nicht der Fall ist, bitte klarstellen.
Die Zuweisung des Strings 'Uuml' an die Variable s geht von der Systemkodierung aus und liefert daher bei Umlauten nicht das gewünschte Ergebnis. UTF8Decode() ist da eindeutiger. Das Ergebnis liegt bereits als WideChar vor, muss also für UTF8Encode nicht weiter behandelt werden.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  s: Widestring;
  wc: Widechar;
begin
  s := UTF8Decode('Uuml');
  if ResolveHTMLEntityReference(s, wc) then
    Button1.Caption := UTF8Encode(wc);
end;  
Edit:
Der eigentliche Fehler ist der Aufruf der Funktion WideCharToString(). Dieser erwartet einen Null-Terminierten WideChar-String. Der ist nicht gegeben.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Bug in WideCharToString

Beitrag von Michl »

Nein, ich habe diese Procedure http://www.lazarusforum.de/viewtopic.php?f=26&t=7132. Habe sie für mich schneller machen wollen und bin dabei auf dieses Problem gestoßen. Um es zu isolieren, habe ich das Minimalbsp. erstellt und zwischenzeitlich geändert! Fehler sieht bei mir so aus:
Dateianhänge
Falsch.jpg
Falsch.jpg (16.28 KiB) 2789 mal betrachtet
Korrekt.jpg
Korrekt.jpg (17.96 KiB) 2789 mal betrachtet

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Bug in WideCharToString

Beitrag von Michl »

Socke hat geschrieben:Edit:
Der eigentliche Fehler ist der Aufruf der Funktion WideCharToString(). Dieser erwartet einen Null-Terminierten WideChar-String. Der ist nicht gegeben.
Ok, ich bräuchte in meinem String die Stelle[0] ... verstehe den Fehler trotzdem nicht. Lt. Embarcadero ist doch ein WideChar eine solche?! Und mit @WideChar habe ich doch einen PWideChar bzw. mit

Code: Alles auswählen

procedure Test1;  //funktioniert
var
  x,y,z,a:integer;
  s:widestring;
  PWC:PWidechar;
  WC:Widechar;
begin
  s:='Uuml';
  PWC:=@WC;
  if ResolveHTMLEntityReference(s,WC) then
    Form1.Caption:=UTF8Encode(WideCharToString(PWC));
end;
kommt das gleiche Ergebnis zu stande (logisch, da Pointer gleich)!

Lt. deiner Quelle benötigt die Function einen PWideChar (WideCharToString( S: PWideChar ):AnsiString;) so wie im Bsp?! Wo ist da der Fehler - ist doch ein Bug oder stehe ich so aufm Schlauch :? ?!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Bug in WideCharToString

Beitrag von Socke »

Michl hat geschrieben:Lt. deiner Quelle benötigt die Function einen PWideChar (WideCharToString( S: PWideChar ):AnsiString;) so wie im Bsp?! Wo ist da der Fehler - ist doch ein Bug oder stehe ich so aufm Schlauch :? ?!
Der Schlauch ist's :D

Zeichenketten werden in vielen Programmiersprachen (unter anderem C und Pascal) Null-Terminiert. Das heißt, dass nach dem letzten gültigen Zeichen der Binärwert 0 kommt. Damit wird angezeigt, dass die Zeichenkette zu Ende ist.
Ein PWideChar kann daher immer zwei Bedeutungen haben:
  • Ein Zeiger auf einen einzelnen WideChar. Typischerweise wird dieser von der Methode verändert (daher der Zeiger).
  • Eine Folge von WideChars, die durch einen WideChar mit dem Wert 0 beendet wird. Das ist ein ganz fast "normaler" WideString. In Pascal werden im Gegensatz zu anderen Sprachen zusätzlich noch Längeninformationen gespeichert, daher fast ganz "normal". Andere Sprachen müssen sich aber auf diese Kennzeichnung des Endes verlassen.
Welche Bedeutung gemeint ist, kann man daher ausschließlich aus der Dokumentation oder dem Quelltext schließen. Die Dokumentation sagt:
WideCharToString converts the null-terminated widechar array S to an ansistring, and returns the ansistring. [...] No validity checking is performed on Src. Passing an invalid pointer, or an improperly terminated array may lead to access violations.
Du greifst die ganze Zeit auf den Speicher zu, der nach deiner Variablen wc kommt. Da du nur mit einzelnen Buchstaben arbeitest, erhältst du auch keine AccessViolation. Trotzdem kannst du damit den Stack deiner Anwendung zerschießen (und dann funktioniert gar nichts mehr).

Die gleiche Technik wird auch häufig bei Arrays von Zeigern verwendet. Ein PPChar ist möglicherweise ein Array von Strings.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Bug in WideCharToString

Beitrag von Michl »

Socke hat geschrieben:Der Schlauch ist's :D
War kein Schlauch, sondern eine Lücke in meinem Halbwissen :wink:
Socke hat geschrieben:Zeichenketten werden in vielen Programmiersprachen (unter anderem C und Pascal) Null-Terminiert.
Das hatte ich anders verstanden und bei Ein nullterminierter String ist ein Zeichen-Array, dessen Index bei 0 beginnt und das mit NULL (#0) endet nur "dessen Index bei 0 beginnt" gelesen und das mit NULL (#0) endet glatt überlesen (obwohl null-terminiert ja schon alles sagt ...) - naja war dann doch etwas spät :oops:

Daß sich hinter einem Pointer, egal ob PWideChar oder sonst einem Pointer, sich nur eine Speicherstelle verbirgt und man selber schauen muss, dass diese dem Typ entspricht, war mir klar. Vorgenanntes eben nicht!

Auf jeden Fall nochmals vielen vielen Dank für die ausführlichen Erklärungen :D :D :D , habe gelernt bei Verwendung von typisierten Zeigern genauer hin zu schauen :!:


Eine Frage noch, ich habe jetzt statt WideCharToString einfach WideCharLenToString genommen, da es ja immer nur ein Zeichen ist, was ResolveHTMLEntityReference zurückgibt oder spricht da was dagegen?!

Code: Alles auswählen

procedure Test1;  //funktioniert
var
  wc:widechar;
begin
  if ResolveHTMLEntityReference('Uuml',wc) then
    Form1.Caption:=UTF8Encode(WideCharLenToString(@wc,1));
end; 

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

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

Re: [gelöst] Bug in WideCharToString

Beitrag von theo »

So würde mMn reichen

Code: Alles auswählen

  if ResolveHTMLEntityReference('Uuml',wc) then 
    Form1.Caption:=UTF8Encode(wc);

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Bug in WideCharToString

Beitrag von Michl »

theo hat geschrieben:So würde mMn reichen

Code: Alles auswählen

  if ResolveHTMLEntityReference('Uuml',wc) then 
    Form1.Caption:=UTF8Encode(wc);
Habs jetzt noch nicht unter Lazarus 1.1 probiert, ob es dann möglich ist, doch unter 1.0.10 funktionierts leider nicht: "unit1.pas(39,20) Error: Can't determine which overloaded function to call"

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

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

Re: [gelöst] Bug in WideCharToString

Beitrag von theo »

Michl hat geschrieben:Habs jetzt noch nicht unter Lazarus 1.1 probiert, ob es dann möglich ist, doch unter 1.0.10 funktionierts leider nicht: "unit1.pas(39,20) Error: Can't determine which overloaded function to call"
Kann sein, sorry. Bei mir geht es mit FPC 2.7.1.
Ist eine Frage des Compilers, nicht der Lazarus Version.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: [gelöst] Bug in WideCharToString

Beitrag von Michl »

theo hat geschrieben:Kann sein, sorry. Bei mir geht es mit FPC 2.7.1.
Ist eine Frage des Compilers, nicht der Lazarus Version.
Habs eben selber auch noch bei 1.1 (FPC 2.7.1) getestet, da geht es, wie du schriebst!

Wenn ich mir das ganze durch den Kopf gehen lasse, ist es doch recht ärgerlich, dass ich den halben Abend gestern damit verbracht habe, ein Feature einer auslaufenden Version zu begreifen. Habe zwar dank Socke auch wieder was gelernt (und das ist sehr gut), doch ziehe ich hieraus jetzt das Fazit, daß ich wohl besser unter einem aktuellem Trunk von Lazarus (also 1.1 mit FPC 2.7.1) entwickeln sollte...

Danke an alle Helfer! In dem Sinn: An die Tasten und gut Coding-Flow!

Michael

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: [gelöst] Bug in WideCharToString

Beitrag von mschnell »

Vorsicht mit dem aktuellen Trunk von fpc. Da werden nun (auch) die "New Strings" unterstützt. Ich hatte bei testest zwar bisher noch keine davon herrührenden Probleme, aber die können durchaus auftreten.

-Michael

Antworten