Xaver
Xaver

Reputation: 1001

Delphi from bytes to struct

I have a next code:

type THead = packed record
  znmpc: byte;
  znmpcch: array [0..1] of char;
  znc, zneispr, zkpd, zkps, nd: byte;
  zb9, zb10, zb11, zb12, zb13, zb14, zb15: byte;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  db: ^THead;
  a: array [0..9] of byte;
begin
  a[7] := 9;
  db := @a;
  ShowMessage(IntToStr(db.nd));
end;

Is this code safe? I'm worried about next thing: size of struct more than size of buffer, and i have a fear about it. The value of members of struct after nd has no meaning for me. I want to know can this code throw an exception in certain circumstances, and if so in what?

Upvotes: 3

Views: 763

Answers (2)

Mehmet Fide
Mehmet Fide

Reputation: 1795

I guess reading db.nd is fine. You will access somewhere in stack which doesn't belong to you. But writing something to this variable can cause catastrophic failure, we can not know.

Also, If you exceed your boundary too much, you can get access violation for reading too:

procedure TForm2.Button1Click(Sender: TObject);
var
  db: THead;
  p: PByte;
begin
  db.nd := 9;
  p := @db;

  ShowMessage(IntToStr(p[7])); // shows 9
  ShowMessage(IntToStr(p[700])); // shows 182 for me?
  ShowMessage(IntToStr(p[70000])); // shows 0
  ShowMessage(IntToStr(p[700000])); // access violation!
end;

It is safer using unions:

type
  THead = packed record
    znmpc: byte;
    znmpcch: array [0..1] of AnsiChar;
    znc, zneispr, zkpd, zkps, nd: byte;
    zb9, zb10, zb11, zb12, zb13, zb14, zb15: byte;
  end;

  THeaderUnion = packed record
    case Integer of
      0: (Head: THead);
      1: (ByteArray: Array[0.. sizeof(THead)-1] of Byte);
  end;

procedure TForm1.Button1Click(Sender: TObject);
Var
  db: THeaderUnion;
begin
 db.ByteArray[7] := 9;
 ShowMessage(IntToStr(db.Head.nd));
end;

Upvotes: 2

Andreas Rejbrand
Andreas Rejbrand

Reputation: 108929

I'd guess it is perfectly safe if you handle it carefully. But you need to be certain that you do not forget that you may not access zb11..zb15. In addition, recall that a char is 1 byte prior to Delphi 2009, and 2 bytes in Delphi 2009 and later versions. Also, maybe it is worth to make the record packed (don't think you need that in this case, but it is never wrong to be pedantically explicit)? Finally, of course you have to be careful so that the array doesn't go out of scope!

Upvotes: 6

Related Questions