AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Padding Bytes herausfinden

Ein Thema von Der schöne Günther · begonnen am 20. Feb 2018 · letzter Beitrag vom 7. Feb 2019
Antwort Antwort
Der schöne Günther

Registriert seit: 6. Mär 2013
6.108 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Padding Bytes herausfinden

  Alt 20. Feb 2018, 12:50
Angenommen folgender Record:

Delphi-Quellcode:
   TMyRecord = record
      a:   Byte;
      // ( 3 Padding Bytes)
      b:   Integer;
   end;
Der Record hat SizeOf() = 8 denn zwischen a und b sind noch drei Byte Luft (zumindest unter Win32).

Kann ich gezielt herausfinden dass von diesen 8 Bytes an Position [1], [2] und [3] Padding Bytes sind?


Ziel: Ich möchte für den Unit-Test einer Hash-Funktion für Records gezielt Padding-Bytes setzen. Ich kann natürlich mit Methoden wie von TBitConverter oder FillChar(..) direkt in den Speicher schreiben, allerdings bekomme ich dann arge Probleme wenn der Record Referenztypen wie Strings oder Interfaces enthält denn dort steht dann arger Müll. Einzige Ausnahme wären Nullen, aber ich möchte die Padding-Bytes in zwei Records ja unterschiedlich haben.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.980 Beiträge
 
Delphi 12 Athens
 
#2

AW: Padding Bytes herausfinden

  Alt 20. Feb 2018, 13:06
Kann ich gezielt herausfinden dass von diesen 8 Bytes an Position [1], [2] und [3] Padding Bytes sind?
Delphi-Quellcode:
var
  rec: TMyRecord;
begin
  if Sizeof(rec.a) < (UIntPtr(@rec.b) - UIntPtr(@rec.a)) then begin
    Writeln('Padding');
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.100 Beiträge
 
Delphi 12 Athens
 
#3

AW: Padding Bytes herausfinden

  Alt 20. Feb 2018, 13:12
Also "Messen", siehe Uwe Raabe,
oder selber berechnen. So schwer ist die Logic nicht.

Bei krumen Sondertypen, wie dem Extended, oder geheimen Typen ala Variant, die nicht gleich als Record erkennbar sind, muß man nur erstmal genauer hinschauen und notfalls ein bissl rumprobieren.



Erstmal kommt es drauf an, wie der Compiler eingestellt ist.
http://docwiki.embarcadero.com/RADSt...ichten_(Delphi)
TMyRecord = packed record enspricht {$A1} .

Früher war es mal {$A4} und aktuell (seit knapp 10 Jahren) ist es meisten {$A8} .

Und dann kann man das alles problemlos ausrechnen.

Delphi-Quellcode:
{$ALIGN 4}

TMySubRecord = record
  x: Word;
  y: Word;
end;
// oder
TMySubRecord = array[0..1] of Word;

TMyRecord = record
  a: Byte;
  // ( 3 Padding Bytes)
  b: Integer;
  c: Int64;
  d: TMySubRecord;
end;
Code:
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
a . . . b b b b c c c c c c c c d d d d
"a" ist 1 Byte, also wird es auf ganz 1-Byte ausgerichtet.
"b" ist 4 Byte, also wird es auf ganz 4-Byte ausgerichtet.
"c" ist 8 Byte, also würde es auf ganz 8-Byte ausgerichtet, aber da ALIGN=4, wird es gekürzt und somit auf ganz 4-Byte ausgerichtet.
"d" ist 4 Byte, aber laut seine "internen" Ausrichtung auf maximal 2 Byte ausgerichtet, also wird es auf ganz 2-Byte ausgerichtet.

Wäre "b" ein Word, würde es auf 2 ausgerichtet und somit 2 Felder nach links rutschen.

Code:
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 - ALIGN 4
a . b b c c c c c c c c d d d d

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 - ALIGN 8
a . b b . . . . c c c c c c c c d d d d . . . .
Am Ende wird der RECORD nochmal mit dem aufgefüllt, was dem größten enthalten Typen entspricht, abgerundet auf das ALIGN.



Das $ALIGN ist sowas wie eine MAXimale Begrenzung für die Ausrichtung.

Und Arrays "quasi" wie PACKED ... sie nehmen das ALIGN ihrer Felder an, welche keinen Freiraum zwischen sich lassen, abgesehn von ihrem eigenen Padding.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (20. Feb 2018 um 13:23 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.108 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Padding Bytes herausfinden

  Alt 20. Feb 2018, 15:59
Vielen Dank euch beiden für die Antworten erst einmal.

Ich hätte gedacht man kann etwas allgemeingültiges finden. Es hängt ja schon von der Reihenfolge der Felder ab, wie der Record deklariert ist. Compiler-Direktiven tun ihr übriges. Von Hand wollte ich da so wenig wie möglich machen.

Ich glaube mein Ziel "Beschreibe alle Padding-Bytes mit X" erreiche ich folgendermaßen:

Delphi-Quellcode:
type
   TMyRecord = record
      a:   Byte;
      // ( 3 Padding Bytes)
      b:   String;
   end;

procedure p();
var
   x, y: TMyRecord;
   bytes_before: TBytes;
   bytes_after: TBytes;
begin
   FillChar(x, SizeOf(x), $FF);
   System.Initialize(x);

   FillChar(y, SizeOf(y), $A5);
   System.Initialize(y);

   // Records sind nun semantisch, aber nicht bitweise gleich
end;
Das Zauberwort war System.Initialize(..), das kannte ich bislang nicht. Wenn der Record für b beispielsweise einen Integer hätte gibt der Compiler sogar völlig berechtigt eine Warnung
Zitat:
H2243 Der Ausdruck benötigt kein Initialize/Finalize
aus.

Wenn ich jetzt nichts übersehen habe ist das perfekt und genau was ich haben wollte!
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.008 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#5

AW: Padding Bytes herausfinden

  Alt 20. Feb 2018, 16:05
Kurz mal die RTTI bemüht:

Delphi-Quellcode:
procedure PrintPaddingBytes(typeInfo: PTypeInfo);
var
  ctx: TRttiContext;
  t: TRttiType;
  f: TRttiField;
  offset: Integer;
begin
  t := ctx.GetType(typeInfo);
  offset := 0;
  for f in t.GetFields do
  begin
    case f.Offset - offset of
      0:;
      1: Writeln('padding at byte ', offset);
    else
      Writeln('padding at bytes ', offset, ' - ', f.Offset - 1);
    end;
    offset := f.Offset + f.FieldType.TypeSize;
  end;
end;
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.108 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Padding Bytes herausfinden

  Alt 20. Feb 2018, 16:35
Super, TRttiField.Offset war mich nicht bewusst.

Jetzt muss ich mich entscheiden. Beides sieht gut aus. Hm...
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Padding Bytes herausfinden

  Alt 21. Feb 2018, 09:26
Meine Records haben häufig eine Clear-Methode, um den Speicher zu Nullen.
Delphi-Quellcode:
type
  TMyRecord = record
    Value1: Byte;
    Value2: string;
    procedure Clear;
  end;

implementation

procedure TMyRecord.Clear;
begin
  Finalize(Self);
  FillChar(Self, SizeOf(Self), #0);
end;
Finalize wird nur benötigt, wenn String, dynamische Array oder Interface-Member vorhanden sind.
Andernfalls meldet der Compiler das.
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.108 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Padding Bytes herausfinden

  Alt 6. Feb 2019, 10:46
Kurz mal die RTTI bemüht:
(…)
Kleiner Nachtrag: Hierbei wird der Fall vergessen wenn das letzte Feld im Record noch Padding hat. Nach der for -Schleife muss man noch einmal den Wert von offset mit t.TypeSize vergleichen. Die Differenz davon sind die letzten Padding-Bytes.


Mein "fillPaddingBytes" sähe dann so aus:

Delphi-Quellcode:
procedure TMyStructHelper.fillPaddingBytes(const pattern: Byte);
var
   ctx: TRttiContext;
   rttiType: TRttiType;
   field: TRttiField;
   offset: Integer;
   rawMemory: PByte;
   index: NativeInt;
begin
   rttiType := ctx.GetType( TypeInfo(TMyStruct) );
   offset := 0;
   rawMemory := @self;
   for field in rttiType.GetFields() do
      begin
         case field.offset - offset of
            0: ;
            1: rawMemory[offset] := pattern;
         else
            for index := offset to Pred(field.Offset) do
               rawMemory[index] := pattern;
         end;
         offset := field.offset + field.FieldType.TypeSize;
      end;

   for index := offset to Pred(rttiType.TypeSize) do
      rawMemory[index] := pattern;
end;
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
672 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Padding Bytes herausfinden

  Alt 7. Feb 2019, 11:32
Delphi-Quellcode:
type
   TMyRecord = record
      a: Byte;
      // ( 3 Padding Bytes)
      b: String;
   end;
   PMyRecord = ^TMyRecord;
Man kann nun direkt die Offsets der Felder ermitteln, auch ohne extended RTTI zu bemühen:

NativeUInt(@PMyRecord(nil)^.a) // offset von a
NativeUInt(@PMyRecord(nil)^.b) // offset von b
etc.
Peter Below
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.108 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: Padding Bytes herausfinden

  Alt 7. Feb 2019, 11:42
Aber der Code gilt nur für TMyRecord und man muss ihn anpassen wenn man an TMyRecord etwas ändert. Eine Methode die auf alle Records passt hat schon was für sich 😎
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:23 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