SRL Archive - Lape

Unexplainable la-pe bug


Gu3st...

2013-12-11 14:26:53

rep+ to the one/those that can explain and post a solution to this peculiar bug!
type
TTest = record
someProcedure : procedure(var var1, var2 : Integer;
const param1, param2 : Integer);
end;

procedure TTest.someProcedureTest(var var1, var2 : Integer;
const param1, param2 : Integer);
begin
writeLn(var1);
var1 := param1;
writeLn(var2);
var2 := param2; // This line should not throw access violation error, but does.

// This line will never get executed due to access violation error:
writeLn(var1, ' ', var2);
end;

var
Test : TTest;
int1, int2 : Integer;

begin
// Assign the pointer to point to Test.someProcedureTest
Test.someProcedure := @Test.someProcedureTest;
// Set int1 to 3000, int2 to -30
int1 := 3000;
int2 := -30;
// Call the procedure with int1, int2, 1 and 2 as params.
// Pay attention to the order of the params: int1 is before int2
Test.someProcedure(int1, int2, 1, 2);
// This line will never get executed due to access violation error:
writeLn(int1, ' ', int2);
end.

Simba's progress report:
Compiled successfully in 219 ms.
-30
1
Exception in Script: Runtime error: "Access violation" at line 13, column 8
Note: line 13 is "var2 := param2" and is the line that throws the error as line 12 (writeLn(var2)) is executed.

What's peculiar is that when we try to print the value of var1 which we set to 3000, it prints "-30" instead (which is var2's value).
Then, when we try to print the value of var2 it proceeds to print "1", which is param1's value and var1's new value instead of "2" which it should have (which is param2's value).

Basically, Lape executes the following instead of what I posted above:
var1 := var2;
writeLn(var1);
var2 := param1;
writeLn(var2);
throw_error_lol('Because fuck you, Zyt3x. You piece of shit.');

@nielsie95; @Dgby714; @Wizzup?;

#YoHoJo4Potato

bonsai

2013-12-11 14:35:02

No explanation here but it works fine if you remote "TTest." from someProcedureTest (i.e. the procedure you give it an address to is not tied to the record).

Gu3st...

2013-12-11 14:36:42

From: bonsai
No explanation here but it works fine if you remote "Test." from someProcedureTest (i.e. the procedure you give it an address to is not tied to the record).
Nice, so basically Lape assumes "TTest." is the first variable, and not var1 as we'd think.
Good find, bonsai; rep+

nielsie95

2013-12-11 15:18:16

The 3000 parameter is hidden in self (try adding WriteLn(Self)). It is because you are mixing a method of an object and a plain method:


WriteLn(@Test.someProcedure);
WriteLn(@Test.someProcedureTest);

But yes, definitely a bug.

Gu3st...

2013-12-11 15:24:53

Wow, that's so weird. :p self (originally a TTest) turns into an integer all of a sudden?
I don't *have* to do it this way I guess, but I felt my script was more organized this way.

Is it an easy fix?

nielsie95

2013-12-11 15:29:39

Try adding "of object" to the method type for now:


TTest = record
someProcedure : procedure(var var1, var2 : Integer;
const param1, param2 : Integer) of object;
end;

Gu3st...

2013-12-11 15:41:23

From: nielsie95
Try adding "of object" to the method type for now:


TTest = record
someProcedure : procedure(var var1, var2 : Integer;
const param1, param2 : Integer) of object;
end;
Compiles and runs, but is extremely slow compared to what it should be…
Tell me, what exactly does lape do differently when I add of object?

nielsie95

2013-12-11 15:46:35

It adds a (hidden) "self" parameter :p

Gu3st...

2013-12-11 16:16:50

Doesn't explain why it's so slow :/

Brandon

2013-12-11 22:31:17

It becomes slower because:

procedure TTest.someProcedureTest(var var1, var2 : Integer; const param1, param2 : Integer);

becomes:

procedure someProcedureTest(Self: TTest^; var var1, var2 : Integer; const param1, param2 : Integer);
and it has to pass and dereference that self/hidden this pointer every time. Shouldn't be a problem at all though.

However, it should not even have a noticeable speed difference at all.. Not sure what you mean by slower because it's the same speed afaict..


Also here's why you need the hidden this parameter:


type
TTest = record
someProcedure : procedure(var T: Integer);
end;

procedure TTest.someProcedureTest(T: Integer);
begin
writeLn(T);
end;

procedure globalSomeProcedureTest(T: Integer);
begin
writeLn(T);
end;

var
T: TTest;
int1: Integer;
Ptr: Pointer;

begin
Ptr := (@T.someProcedureTest);
writeln('Pointer To Object Func: ', Ptr);
writeln('Address of object Func: ', @T.someProcedureTest, #13#10);

Ptr := @globalSomeProcedureTest;
writeln('Pointer to global Func: ', Ptr);
writeln('Address of global Func: ', @globalSomeProcedureTest);
end.

[BANANA]
Pointer To Object Func: 0x6210
Address of object Func: (record [0]procedure(<Int32>); end).procedure(Int32) of object (0x6210)

Pointer to global Func: "globalSomeProcedureTest"::0x6348
Address of global Func: procedure(Int32) ("globalSomeProcedureTest"::0x6348)
[/BANANA]

Ahh. The difference between a reference and a pointer and a reference to an object function and a pointer to an object function in Lape is amusing.
See.. the pointer to the object function loses all its type information while every other type of pointer and reference keeps its type info. A cast doesn't even fix it. :l

Hidden this does fix it and shouldn't slow anything down. Just extra typing is all.

Gu3st...

2013-12-12 08:51:08

Yes, you're right; that didn't affect the speed at all; it was a silent error which I got in another function that slowed things down.
Thanks a lot for the elaborate explanation :)

It just seemed extremely weird when Lape started assigning values to variables before I told it to.

I actually kind of have to remake my whole script now, though… That's a bummer.