SRL Archive - OSR Help

Access Violation Pointer Arithmetic


Brandon

2013-08-30 19:47:20


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

{Function Malloc(Size: Uint32): Pointer;
var
Ptr: Array Of Byte;
Begin
SetLength(Ptr, Size);
Result := @Ptr;
End;}

var
P: Array Of Byte;
begin
SetLength(P, 10);
Memset(@P, 65, 5);
writeln(P);
end;

Why is this access violaton? The array is 10 bytes in size.. All I'm doing is iterating it via a pointer and setting 5 bytes to 'A' aka byte 65..

bgtemp

2013-09-01 23:31:14




Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
i : integer;
Begin
For i := 0 To Size Do
begin
Ptr := Data + i ;
Ptr^ := Value+1;
writeln(i);
writeln(Ptr);
end;
writeln('Inside function:');
Ptr := Data;
writeln(Ptr);
writeln(Data);
End;

var
P: Array Of Byte;
begin
SetLength(P, 10);
writeln('Before:');
writeln(@P);
writeln('-------');
Memset(@P, 65, 5);
writeln('-------');
writeln('After:');
writeln(@P);
writeln(P); //Exception in Script: Runtime error: "Access violation"
end.

Before:
"P"::0x116C0860 ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Inside function:
"P"::0x16D35AE0 (66) //Ptr
"P"::0x16D35AE0 // Data

After:
"P"::0x116C0860

You don't have Access violation inside this function ,but anyway it looks like this function makes pointer P no more assigned to the start of array.



Edit ———————————————————————————————

I think I can reduce it to few lines:



var
P: Array Of Byte;
Ptr: ^Byte;
begin
SetLength(P, 10);
writeln('Before:');
writeln(@P);
writeln('-------');

Ptr := @P +1;
//Ptr^ := 65; // Exception TLPThread.Destroy: Access violation
writeln(Ptr);

writeln('-------');
writeln('After:');
writeln(@P);

end.

bgtemp

2013-09-02 01:05:53

I know nothing about LAPE ,but Simba told me that:

@P is not the adress of the array ,or adress of the first element of array ,but adress of the pointer to the array. So if you do:

Ptr := @P;
Ptr^ := value;

you are changing adress assigned to the array named "P". When Simba is looking for array "P" it finds only stack of junks there ,so thats why access violaton occurs.

I think it should be done this way:

var
P: Array Of Byte;
Ptr: ^integer;
Bptr : ^byte;
begin
SetLength(P, 10);

writeln(@P);
Ptr := @P;
Bptr := Ptr^;
end.

,but:

Exception in Script: Can't assign "Int32" to "^UInt8" at line 15, column 8

stata

2013-09-02 01:20:45

From: bgtemp
I know nothing about LAPE ,but Simba told me that:

@P is not the adress of the array ,or adress of the first element of array ,but adress of the pointer to the array. So if you do:

Ptr := @P;
Ptr^ := value;

you are changing adress assigned to the array named "P". When Simba is looking for array "P" it finds only stack of junks there ,so thats why access violaton occurs.

I think it should be done this way:

var
P: Array Of Byte;
Ptr: ^integer;
Bptr : ^byte;
begin
SetLength(P, 10);

writeln(@P);
Ptr := @P;
Bptr := Ptr^;
end.

,but:

Exception in Script: Can't assign "Int32" to "^UInt8" at line 15, column 8


I dunno about this. P is the array, so @P should be the address of the array (the first element). He is using @P as the pointer to the array P, which is correct. Unless the @ operator means double pointer, I don't see how @P could point to the the array's pointer

EDIT: Actually, this might indicate that Lape treats array names as the pointer to the array. This was actually something I was wondering about but no-one seemed to know definitively (dunno why, easy check). I've been told by most that to get array P's pointer, I'd need to use @P, but if what you're saying is correct it seems P would be the pointer to the array after all.

bgtemp

2013-09-02 02:07:14

Just found some hacky way to bypass Can't assign "Int32" to "^UInt8" :spot::

function HexToDec(Str: string): Integer;
var
i, M: Integer;
begin
Result:=0;
M:=1;
Str:=AnsiUpperCase(Str);
for i:=Length(Str) downto 1 do
begin
case Str[i] of
'1'..'9': Result:=Result+(Ord(Str[i])-Ord('0'))*M;
'A'..'F': Result:=Result+(Ord(Str[i])-Ord('A')+10)*M;
end;
M:=M shl 4;
end;
end;

var
P: Array Of Byte;
Ptr: ^integer;
Bptr : ^byte;
i,t : integer;
begin
SetLength(P, 10);
for i := 0 to 9 do P[i] := i;

Ptr := @P;
writeln(Ptr);
t := -HexToDec(ReplaceRegExpr('"P"::0x| (.*)',tostr(Ptr),'',false));

writeln('TEST !');
for i := 0 to 9 do
begin
Bptr := @P+t+Ptr^+i;
writeln(Bptr);
end;
end.


Works.

stata

2013-09-02 02:11:13

From: stata
I dunno about this. P is the array, so @P should be the address of the array (the first element). He is using @P as the pointer to the array P, which is correct. Unless the @ operator means double pointer, I don't see how @P could point to the the array's pointer

EDIT: Actually, this might indicate that Lape treats array names as the pointer to the array. This was actually something I was wondering about but no-one seemed to know definitively (dunno why, easy check). I've been told by most that to get array P's pointer, I'd need to use @P, but if what you're saying is correct it seems P would be the pointer to the array after all.



ok just ran the following. Weird results. Not sure what to make of it…
All I know is @P should be the pointer to the array.

var
p: Array of Integer;

begin
p := [1,2,3];
writeln(p); //prints [1,2,3]
writeln(p^); //prints 1, so seems to indicate p is pointing to the first element
writeln((p+4)^); //prints 1, wtf?
writeln(@p); //prints "p"::0xCBB60C0 ([1, 2, 3]), so @p is a memory address, but of what?
writeln(@p+4); //prints 0xC9D00D4 ([])

also, if I run (p+4)^ when p is an Array[0..2] of Integer, it gives me the following error
Exception in Script: Operator "Plus" not compatible with types "array [0..2] of Int32" and "Int32" at line 10, column 13

so what's pointing to what?


Edit:
var
p: Array[0..2] of Integer;

begin
p := [1,2,3];
writeln(p); //prints [1,2,3]
writeln((@p+4)^); //prints [2,3,0]

so this kind of worked as intended, except why the hell does it print a whole array? I expected the second writeln to print just 2
Also, how come with dynamic integer arrays, the second writeln only prints []?

bgtemp

2013-09-02 02:22:17

OK ,let's fix code from OP:


function HexToDec(Str: string): Integer;
var
i, M: Integer;
begin
Result:=0;
M:=1;
Str:=AnsiUpperCase(Str);
for i:=Length(Str) downto 1 do
begin
case Str[i] of
'1'..'9': Result:=Result+(Ord(Str[i])-Ord('0'))*M;
'A'..'F': Result:=Result+(Ord(Str[i])-Ord('A')+10)*M;
end;
M:=M shl 4;
end;
end;

Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
BPtr: ^Byte;
Ptr: ^integer;
t ,i: integer;
Begin
Ptr := Data;
t := -HexToDec(ReplaceRegExpr('"P"::0x| (.*)',tostr(Ptr),'',false));
For i := 0 To Size Do
begin
Bptr := Ptr+t+Ptr^+i;
BPtr^ := Value;
end;


End;


var
P: Array Of Byte;
begin
SetLength(P, 10);
Memset(@P, 65, 5);
writeln(P);
end;

vuala

Compiled successfully in 312 ms.
[65, 65, 65, 65, 65, 65, 0, 0, 0, 0]
Successfully executed.


Edit ————————

@UP
writeln(@p); //prints "p"::0xCBB60C0 ([1, 2, 3]), so @p is a memory address, but of what?


As I've said above, 0xCBB60C0 is an adress of the a array and p is the name of array.
To get to this array you need to create pointer pointing this addres.

stata

2013-09-02 02:27:03

Ok, something interesting I figured out about arrays and pointers in lape while testing

With dynamic arrays, the name of the array (with @ operator) is not pointing to the first element of the array. It's pointing to the array. The address of the first element of the array is somewhere else entirely. The subsequent elements are found right next to it in memory as expected however.

However, with arrays on the stack, the name of the array (with @ operator) DOES point to the first element of the array.

So since you're using dynamic arrays here, what you need to do is deal with the address of the first element and use this as the "base pointer" for accessing the rest of the elements in the array


program pointercheck;

var
p: Array of Integer;
q: Array[0..2] of Integer;

begin
p := [1,2,3];
writeln(@p);
writeln(@p[0]);
writeln((@p[0])^);
writeln((@p[0]+4)^);

writeln('——–');
writeln(@q);
writeln(@q[0]);
writeln((@q[0])^);

end.

OUTPUT:
"p"::0xCC990B0 ([1, 2, 3])
0xCC99418 (1)
1
2
——–
"q"::0xCC99170 ([0, 0, 0])
"q"::0xCC99170 (0)
0

stata

2013-09-02 02:39:08

From: stata
Ok, something interesting I figured out about arrays and pointers in lape while testing

With dynamic arrays, the name of the array (with @ operator) is not pointing to the first element of the array. It's pointing to the array. The address of the first element of the array is somewhere else entirely. The subsequent elements are found right next to it in memory as expected however.

However, with arrays on the stack, the name of the array (with @ operator) DOES point to the first element of the array.

So since you're using dynamic arrays here, what you need to do is deal with the address of the first element and use this as the "base pointer" for accessing the rest of the elements in the array


Given all this, here is my simple fix to Brandon's code
Note how the only thing I changed was indexing the pointer he passes to his function

Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
P: Array Of Byte;
begin
SetLength(P, 10);
Memset(@P[0], 65, 5);
writeln(P);
end;

bgtemp

2013-09-02 02:52:36

From: stata
Given all this, here is my simple fix to Brandon's code
Note how the only thing I changed was indexing the pointer he passes to his function

Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

{Function Malloc(Size: Uint32): Pointer;
var
Ptr: Array Of Byte;
Begin
SetLength(Ptr, Size);
Result := @Ptr;
End;}

var
P: Array Of Byte;
begin
SetLength(P, 10);
Memset(@P[0], 65, 5);
writeln(P);
end;


Yea, it's a little bit shorter then my fix:D I didn't think this way. But anyway now we know how it works.

Edit:

So (from your second post above), if Brandon used static array:

var
P: Array [0..9]Of Byte;

he wouldn't get access violation.

Edit2:
With dynamic arrays, the name of the array (with @ operator) is not pointing to the first element of the array. It's pointing to the array. The address of the first element of the array is somewhere else entirely


In dynamic arrays @P is actually a pointer to the first element of array. It's value is an address of the first value in array.

In static arrays @P is not a pointer ,it's first value of array itself.

stata

2013-09-02 03:02:05

From: bgtemp
Yea, it's a little bit shorter then my fix:D I didn't think this way. But anyway now we know how it works.

Edit:

So (from your second post above), if Brandon used static array:

var
P: Array [0..9]Of Byte;

he wouldn't get access violation


Just ran it, works like a charm lol.
Weird we never tested this. Guess we all just assumed this worked like C :P

Brandon, I think these points would go nicely in that very thorough Lape guide you've written

Brandon

2013-09-02 03:29:01

Wtf? How can @P != @P[0].. I see what you guys are saying and yes using @P[0] works but seriously?!
It makes absolutely no sense to have the ebp point to a random location for heap arrays and to base[0] for stack arrays. The assembly is borked?

That's like having a heap array start at index 1 and stack arrays at 0.

K when I get home from work ill edit that tutorial.. It's weird though because the code in the tutorial still works and off the top of my head, I think it is using @Ptr and not @Ptr[0]. Ill have to check again.
I also remember using the same memset function using an @stringvariablehere and it worked just fine.

However, nice discovery and tests :) There are side effects to this though..



Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
p: array of byte;
ptra, ptrb: Pointer;
begin
setlength(p, 10);
ptra := @p;
ptrb := @p[0];

writeln(Uint32(ptra));
writeln(Uint32(ptrb));
writeln(Uint32(@P) - Uint32(@P[0])); //Useless.. P[0] is at random offset from @P.
writeln(Uint32(@P[1] - Uint32(@P[0])); //offset of 1 byte as expected.
end;


And in the following, you'll notice that it works just fine using @StringVariable instead of @StringVariable[0] which does NOT work even though a string is an array of bytes/chars:


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o'];
s := '';

writeln(length(c));
setlength(s, length(c));
//MemSet(@s, 0, length(c)); //uncomment this line and you'll see the difference..
MemSet(@s[0], 0, length(c)); //Lol.. fail..

for i := 0 to sizeof(c) do
begin
s := s + c[i];
end;
writeln(s);
end.



And finally the one you guys already figured out(absolutely ridiculous):


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
Ptr: ^Integer;
TIA: array[0..4] of integer;
TDIA: array of integer;
begin
TIA := [1, 2, 3, 4, 5];
TDIA := [1, 2, 3, 4, 5];

writeln('Printing stack array');
Ptr := @TIA; //Does not need indexing..
For 0 To High(TIA) do
begin
writeln(Ptr^);
Inc(Ptr);
end;

writeln(#13#10 + 'Printing heap array');
Ptr := @TDIA[0]; //Needs indexing..
For 0 To High(TIA) do
begin
writeln(Ptr^);
Inc(Ptr);
end;
end;


Just makes me wanna stop using Lape tbh.. so many things wrong..

stata

2013-09-02 11:58:53

From: Brandon
Wtf? How can @P != @P[0].. I see what you guys are saying and yes using @P[0] works but seriously?!
It makes absolutely no sense to have the ebp point to a random location for heap arrays and to base[0] for stack arrays. The assembly is borked?

That's like having a heap array start at index 1 and stack arrays at 0.

K when I get home from work ill edit that tutorial.. It's weird though because the code in the tutorial still works and off the top of my head, I think it is using @Ptr and not @Ptr[0]. Ill have to check again.
I also remember using the same memset function using an @stringvariablehere and it worked just fine.

However, nice discovery and tests :) There are side effects to this though..



Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
p: array of byte;
ptra, ptrb: Pointer;
begin
setlength(p, 10);
ptra := @p;
ptrb := @p[0];

writeln(Uint32(ptra));
writeln(Uint32(ptrb));
writeln(Uint32(@P) - Uint32(@P[0])); //Useless.. P[0] is at random offset from @P.
writeln(Uint32(@P[1] - Uint32(@P[0])); //offset of 1 byte as expected.
end;


And in the following, you'll notice that it works just fine using @StringVariable instead of @StringVariable[0] which does NOT work even though a string is an array of bytes/chars:


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
c : Array of Char;
s : string;
i : integer;
begin
c := ['h', 'e', 'l', 'l', 'o'];
s := '';

writeln(length(c));
setlength(s, length(c));
//MemSet(@s, 0, length(c)); //uncomment this line and you'll see the difference..
MemSet(@s[0], 0, length(c)); //Lol.. fail..

for i := 0 to sizeof(c) do
begin
s := s + c[i];
end;
writeln(s);
end.



And finally the one you guys already figured out(absolutely ridiculous):


Procedure MemSet(Data: Pointer; Value: Byte; Size: Integer);
var
Ptr: ^Byte;
Begin
For Ptr := Data To Data + Size Do
Ptr^ := Value;
End;

var
Ptr: ^Integer;
TIA: array[0..4] of integer;
TDIA: array of integer;
begin
TIA := [1, 2, 3, 4, 5];
TDIA := [1, 2, 3, 4, 5];

writeln('Printing stack array');
Ptr := @TIA; //Does not need indexing..
For 0 To High(TIA) do
begin
writeln(Ptr^);
Inc(Ptr);
end;

writeln(#13#10 + 'Printing heap array');
Ptr := @TDIA[0]; //Needs indexing..
For 0 To High(TIA) do
begin
writeln(Ptr^);
Inc(Ptr);
end;
end;


Just makes me wanna stop using Lape tbh.. so many things wrong..


Lol, I know, weird stuff.

Yeah, strings and char arrays aren't the same unfortunately. I don't remember where I heard this, but apparently the first index of the string (string[0]) contains the size of the string since strings in simba don't have a null terminating character (just checked).
So to get the beginning of the string, you actually have to use @string[1], which they decided to make the same as @string for convenience I guess lmao.

So for static arrays, @array = @array[0], but for strings, @string = @string[1].