Hello,
Although the conversation has been dry for many months, I am publishing this research here because it will avoid multiplying new topics and because the title of this topic, which interests me, fits very well:
TypeInfo() - what is it? After a few tests, it seems that TypeInfo() doesn't just return the address of the struct of variable's type.
It also updates part of the memory in RTTI at compile time (no doubt for practical reasons).
To demonstrate this, here's a little program with two basic records and a procedure that simply displays a series of bytes around an address to scan memory:
(Compiler : fpc version 3.2.2 - System 32 bits - OS : Linux/Ubuntu)
program Test4;
uses typinfo,sysutils;
type aR = Record a,b : byte; end;
bR = Record b : byte; end;
var a : aR; b : bR; p : pointer;
procedure bytes(p : pointer; p0 : integer; nb : word); //Show nb bytes from p[p0] and write them in the console.
var i : word;
begin
for i:=0 to nb-1 do begin
if i mod 16 = 0 then write(IntToHex(sizeUInt(p+p0+i),8),' : ');
write(IntToHex(pbyte(p+p0+i)^,2),' ');
if i mod 16 = 15 then writeln else if i mod 4 = 3 then write('|');
if i mod 128 = 127 then writeln;
end;
writeln;
end;
BEGIN
p:=nil; with a do begin a:=0; b:=0; end; with b do b:=0; //Initialization of the variables (in case - maybe not really necessary here)
writeln('type(b)[-128] : '); bytes(PTypeInfo(TypeInfo(b)),-128,256); //Show 128 bytes before and from the begining of TTypeInfo struct bR.
// p:=PTypeInfo(TypeInfo(a));
END.
The penultimate line is currently inactive. If we run this program, this is what we get:
type(b)[-128] :
080B1050 : 28 1C 0C 08 |9C 40 0C 08 |24 48 0C 08 |00 00 00 00
080B1060 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080B1070 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080B1080 : 00 00 80 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080B1090 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080B10A0 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080B10B0 : 00 00 00 00 |0D 02 62 52 |00 00 00 00 |01 00 00 00
080B10C0 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |B4 10 0B 08
080B10D0 : 0D 02 62 52 |B4 10 0B 08 |01 00 00 00 |01 00 00 00
080B10E0 : 2C 29 0B 08 |00 00 00 00 |D0 10 0B 08 |0E A4 04 08
080B10F0 : 3E A4 04 08 |26 A4 04 08 |26 A4 04 08 |3E A4 04 08
080B1100 : 3E A4 04 08 |3E A4 04 08 |14 A4 04 08 |3E A4 04 08
080B1110 : 26 A4 04 08 |1A A4 04 08 |32 A4 04 08 |1A A4 04 08
080B1120 : 3E A4 04 08 |38 A4 04 08 |32 A4 04 08 |3E A4 04 08
080B1130 : 3E A4 04 08 |38 A4 04 08 |38 A4 04 08 |20 A4 04 08
080B1140 : 08 A4 04 08 |08 A4 04 08 |3E A4 04 08 |3E A4 04 08
The TType Info structure of record b starts at the beginning of the second block (080B10D0 : 0D 02 62 52). There's nothing notable in the 1st block, apart from a few bytes at the end corresponding to the
BaseTypeInit part of record bR (from 080B10B4 : 0D 02 62 52).
But now, if we activate the penultimate line (deleting the '//') and run the program again, we get this:
type(b)[-128] :
080A4080 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080A4090 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |00 00 00 00
080A40A0 : 00 00 00 00 |0D 02 61 52 |00 00 00 00 |02 00 00 00
080A40B0 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |A4 40 0A 08
080A40C0 : 0D 02 61 52 |A4 40 0A 08 |02 00 00 00 |02 00 00 00
080A40D0 : 5C 59 0A 08 |00 00 00 00 |5C 59 0A 08 |01 00 00 00
080A40E0 : C0 40 0A 08 |0D 02 62 52 |00 00 00 00 |01 00 00 00
080A40F0 : 00 00 00 00 |00 00 00 00 |00 00 00 00 |E4 40 0A 08
080A4100 : 0D 02 62 52 |E4 40 0A 08 |01 00 00 00 |01 00 00 00
080A4110 : 5C 59 0A 08 |00 00 00 00 |00 41 0A 08 |FE A3 04 08
080A4120 : 2E A4 04 08 |16 A4 04 08 |16 A4 04 08 |2E A4 04 08
080A4130 : 2E A4 04 08 |2E A4 04 08 |04 A4 04 08 |2E A4 04 08
080A4140 : 16 A4 04 08 |0A A4 04 08 |22 A4 04 08 |0A A4 04 08
080A4150 : 2E A4 04 08 |28 A4 04 08 |22 A4 04 08 |2E A4 04 08
080A4160 : 2E A4 04 08 |28 A4 04 08 |28 A4 04 08 |10 A4 04 08
080A4170 : F8 A3 04 08 |F8 A3 04 08 |2E A4 04 08 |2E A4 04 08
Note that the 1st block has largely changed. It contains the type of the previous record aR (from 080A40C0 : 0D 02 61 52). At 080A40CC, there's 02 00 00 00, corresponding to the number of elements (2) in aR, followed by the pairs (PPointer of variable type and offset of variable content from @a) 5C 59 0A 08 |00 00 00 00 and 5C 59 0A 08 |01 00 00 00 for theses two elements in aR.
This was not the case when the penultimate line was inactive.What's more, as this line comes after the instructions, it means that this change by TypeInfo(a) could not have taken place in run time.
Obviously, this remains to be confirmed. I'm not an expert, I'm just discovering this. In other tests, when the penultimate line is inactive, we see the previous record, but only with some of the elements of the previous record - only variables containing a structure).
In any case, if this is indeed the case, it means that an indirect reading of the RTTI (or even worse, an indirect writing), as I've just done, is flawed. The direct use of the TypeInfo()
(or more securely PTypeInfo(TypeInfo()) ) function is therefore - at the very least - recommended for each type structure.
Finally, something else after further tests: if you put all the records in a record and do a TypeInfo() only on it, the sub-records will also be 'updated' in memory recursively. (also to be confirmed)
(Edit : Changed 'code' to 'quote' in the two last windows to suppress the unexpected colors -it's better like that-)