Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi RTTI-Bugs? (https://www.delphipraxis.net/180250-rtti-bugs.html)

himitsu 5. Mai 2014 08:07

Delphi-Version: XE5

RTTI-Bugs?
 
Moin,

kennt jemand weitere Fehler in der RTTI?
  • falsche Daten bei Sets über 8 Byte (mehr als 64 Elemente)
    Das resultiert dann in falschen TypeSize in der RTTI
  • bei Array-Property (TRttiIndexedProperty) fehlt der Indexbezeichner, bzw. der wird direkt zum Index des Arrays gezählt, wobei aber der Wert dieser Angabe verloren geht.
    Das "wobei" erkennt man auch an dem Eintrag zum "Indexbezeichner" in der OH.
  • einige ToString-Methoden der RTTI, womit man die Deklaration (teilweise) abfragen kann, lösen gern Zugriffsverletzungen aus, wenn sie mit einem seltenern Sonderfall des Aufbaus zusammenstoßen, oder wenn nicht alle nötigen RTTI-Infos einkompiliert wurden.
    (nja, muß man das halt selber in Text übersetzen, was allerdings nicht immer so einfach ist, da nötige Basisfunktionen nicht öffentlich zugänglich sind ... zum Glück kann man da notfalls via RTTI ran, oder man kopiert die Funktionen, wenn man den Quellcde hat)


  • Enums mit manuellen Werten (
    Delphi-Quellcode:
    type TMyEnum = (one, two=1, tree=7);
    ) fehlt in der die RTTI die Liste mit den Aufzählungswerten.
    Gut, das liegt vermutlich an der Art der Liste (#0-terminierte Stringliste), aber man hätte z.B. den fehlenden/übersprungenen Werten einen automatischen "Namen" verpassen können.
    (mein Vorschag wäre einfach eine Zahl, welche dem Wert entspricht, aber dieser "Fehler" existiert nun schon seit so vielen Jahrzehnten ... inzwischen ist das schon ein "Feature")


Vorallm der erste Punkt ist ein großes Problem, denn dort sind wirklich die grundlegenden RTTI-Rohdaten das Problem.
Außerdem wird ein Set, vorallem in der neuen RTTI, als "ordinaler" Typ behandelt, zusammen mit Enums, Integer und Chars, und das geht nunmal nur bis 8 Byte gut.
Die neue RTTI geht über TTypeData.OrdType, für die Größenbestimmung und da sind bei mehr als 8 Byte falsche/ungültige Werte enthalten.


Ein QC kommt demnächst. (erstmal sehn was sich noch für Fehler anfinden)



Meine Test-Daten, für den ersten Punkt:
Delphi-Quellcode:
type
  TMyEnum1 = 0..5; // 1 ... 8-1
  TMySet1  = set of TMyEnum1; // 1 Byte

  TMyEnum2 = 0..15; // 8 ... 16-1
  TMySet2  = set of TMyEnum2; // 2 Byte

  TMyEnum4 = 0..30; // 16 ... 32-1
  TMySet4  = set of TMyEnum4; // 4 Byte

  TMyEnum8 = 0..33; // 32 ... 64-1
  TMySet8  = set of TMyEnum8; // 8 Byte

  TMyEnum20 = 0..155; // ... 160-1
  TMySet20  = set of TMyEnum20; // 20 Byte

  TMyEnum32 = 0..250; // ... 256-1
  TMySet32  = set of TMyEnum32; // 32 Byte (multiple of 4)

  TMyEnum_1 = 0..$70;
  TMyEnum_2 = 0..$7F00;
  TMyEnum_4 = 0..$7FFF0000;
  TMyEnum_4u = 0..$FFFF0000;

  TMyClass = class abstract
    FField:     Integer;
    FMyField1:  TMySet1;
    FMyField2:  TMySet2;
    FMyField4:  TMySet4;
    FMyField8:  TMySet8;
    FMyField32: TMySet32;
    FMyField_1: TMyEnum_1;
    FMyField_2: TMyEnum_2;
    FMyField_4: TMyEnum_4;
    FMyField_4u: TMyEnum_4u;
    function Getter(A, B: string; Index: Integer):      TMySet4; virtual; abstract;
    procedure Setter(A, B: string; Index: Integer; Value: TMySet4); virtual; abstract;
    property X[A, B: string]: TMySet4 index 3 read Getter write Setter;
  published
    property I1: Integer index 1 read FField write FField             default 3;
    property I2: Integer index 2 read FField write FField stored False         ;
    property I3: Integer index 3 read FField write FField stored False default 3;
  end;
Und das, was man aus der RTTI auslesen kann: (als //-Kommentare sind die richtigen Werte enthalten, bzw. eine Erklärung)
Delphi-Quellcode:
// MinValue..MaxValue {TypeSize ClassName}

TMyEnum1 = {Integer}0..5; {Size=1 TRttiOrdinalType}

TMySet1 = set of TMyEnum1; {Size=1 OrdType=1=otUByte TRttiSetType}

TMyEnum2 = {Integer}0..15; {Size=1 TRttiOrdinalType}

TMySet2 = set of TMyEnum2; {Size=2 OrdType=3=otUWord TRttiSetType}

TMyEnum4 = {Integer}0..30; {Size=1 TRttiOrdinalType}

TMySet4 = set of TMyEnum4; {Size=4 OrdType=5=otULong TRttiSetType}

TMyEnum8 = {Integer}0..33; {Size=1 TRttiOrdinalType}

TMySet8 = set of TMyEnum8; {Size=1343671120 OrdType=255 TRttiSetType}
// SizeOf() = 8
// OrdType = invalid

TMyEnum20 = {Integer}0..155; {Size=1 TRttiOrdinalType}

TMySet20 = set of TMyEnum20; {Size=1 OrdType=1 TRttiSetType}
// SizeOf() = 20
// OrdType = invalid

TMyEnum32 = {Integer}0..250; {Size=1 TRttiOrdinalType}

TMySet32 = set of TMyEnum32; {Size=1 OrdType=1 TRttiSetType}
// SizeOf() = 32
// OrdType = invalid

TMyEnum_1 = {Integer}0..112; {Size=1 TRttiOrdinalType}

TMyEnum_2 = {Integer}0..32512; {Size=2 TRttiOrdinalType}

TMyEnum_4 = {Integer}0..2147418112; {Size=4 TRttiOrdinalType}

TMyEnum_4u = {Cardinal}0..-65536; {Size=4 TRttiOrdinalType}
// if MinValue > MaxValue then Cardinal

TMyClass = class {Package1.bpl Unit14.TMyClass Instance Size=4 TRttiInstanceType}
  public
    FField: Integer;
    FMyField1: TMySet1;
    FMyField2: TMySet2;
    FMyField4: TMySet4;
    FMyField8: TMySet8;
    FMyField32: TMySet32;
    FMyField_1: TMyEnum_1;
    FMyField_2: TMyEnum_2;
    FMyField_4: TMyEnum_4;
    FMyField_4u: TMyEnum_4u;
    function Getter(A: string; B: string; Index: Integer): TMySet4; virtual; {Index=0 Addr=$237B23D8}
    procedure Setter(A: string; B: string; Index: Integer; Value: TMySet4); virtual; {Index=1 Addr=$237B23E0}
    property X[A: string; B: string; Index: Integer]: TMySet4 read _Getter write _Setter;
    // TRttiIndexedProperty.ToString liefert für "X" nur eine "Zugriffsverletzung bei Adresse 6F687465. Lesen von Adresse 6F687465"
    // es sollte eigentlich "property X[A: string; B: string; Index: Integer]: TMySet4" liefern, was aber nicht am Set liegt
  published
    // für die Namen der Setter/Getter hab ich noch keine Übersetztung eingeaut
    property I1: Integer index 1 read _Field0004 write _Field0004 default 3;
    property I2: Integer index 2 read _Field0004 write _Field0004;
    property I3: Integer index 3 read _Field0004 write _Field0004 default 3;
  end;

Union 5. Mai 2014 08:12

AW: RTTI-Bugs?
 
Was mir seit langem übel aufstößt ist fehlende komplette RTTI für Records und dort insbesondere die "alten" strings.

himitsu 5. Mai 2014 08:27

AW: RTTI-Bugs?
 
In der alten RTTI?
Published-Felder sollten aber dennoch vorhanden sein. :gruebel: (published gibt es im Record nicht)


In der neuen "erweiterten RTTI" sind die eigentlich vorhaden. (siehe der Anhang in http://www.delphipraxis.net/180247-r...fahrungen.html)


[add]
Delphi-Quellcode:
type
  TMyRecord = record
    A: Byte;
    B: Integer;
    C: ShortString;
    D: string[3];
    E: string;
    property F: Integer read B;
    procedure G;
  end;
Und über die RTTI generiert:
Delphi-Quellcode:
TMyRecord = record {Package1.bpl Unit14.TMyRecord Managed Record Size=272 TRttiRecordType}
  public
    { 0} A: Byte;
    { 4} B: Integer;
    { 8} C: ShortString;
    {264} D: {unknown};
    {268} E: string;
    procedure G; {Addr=$26B37698}
  end;
Warum gerade der eine ShortString mit Längenangabe nicht geht, müsste ich nochmal prüfen. (mir war so, als gingen die)


[add2]
OK, das Problem besteht erstmal nur bei eingebettenten Strings.
Delphi-Quellcode:
type
  TMyStr = string[3];
  TMyRecord = record
    A: Byte;
    B: Integer;
    C: ShortString;
    D: TMyStr;
    E: string;
    property F: Integer read B;
    procedure G;
  end;
Delphi-Quellcode:
TMyStr = string[3]; {Package1.bpl Unit14.TMyStr Size=4 TRttiStringType}

TMyRecord = record {Package1.bpl Unit14.TMyRecord Managed Record Size=272 TRttiRecordType}
  public
    { 0} A: Byte;
    { 4} B: Integer;
    { 8} C: ShortString;
    {264} D: TMyStr;
    {268} E: string;
    procedure G; {Addr=$23AC7684}
  end;
Dabei fällt mir ein, daß es auch ein Problem mit Sets gab.
Delphi-Quellcode:
set of TEnum
geht, aber bei
Delphi-Quellcode:
set of (one, two, tree);
knallt es oftmals.

Stevie 8. Mai 2014 07:26

AW: RTTI-Bugs?
 
Nur damit die Begrifflichkeiten nicht irreführen:
Es gibt keine alte und neue RTTI, es gibt nur eine RTTI. Das Zeugs in der Rtti.pas greift nach wie vor auf die Strukturen in der TypInfo.pas zu. Was neu ist, ist, dass die vom Compiler generierten Informationen erweitert wurden (in Bezug auf nicht published Member, Attribute etc). Aber auch die könnte man, wenn man mutig genug ist, nur mit der TypInfo.pas auslesen.

Außerdem kannst du dir mind einen QC Eintrag sparen, denn die indexed Property wird unter XE6 korrekt ausgegeben.

himitsu 8. Mai 2014 10:24

AW: RTTI-Bugs?
 
Die Struktur der RTTI wurde erweitert und es stehen jetzt standardmäßig zu mehr Dingen Daten darin, welche es früher nicht gab, wie z.B. private Felder.
Viele der neuen Infos werden von den TRtti-Klassen direkt aus den Record-Strukturen gelesen, ohne daß es da neue Ausleseprozeduren in der TypInfo dafür gibt.
Und es gibt die neuen OOP-mäßige Klassenstruktur, zum Auflisten der Daten.

Mindestens 3 Exceptions gab es in XE6 auch noch, beim Auflisten der kompletten RTTI eines gewissen Programmes,
aber ich weiß jetzt auf die Schnelle nicht, welche das waren. (zumindestens waren es weniger, als im XE3)


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:34 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