SRL Archive - Lape

Access violation


honeyhoney

2015-02-15 15:29:19

Apparently there is no difference between

exampleVar: exampleRecord = ['Bank chest we want to use', ['Bank', 'chest']];
and
exampleVar: exampleRecord;
exampleVar := ['Bank chest we want to use', ['Bank', 'chest']];

However, when using the first snippet of code I end up with access violations in the second iteration of the loop (below).
The second snippet works no problem.

Hopefully someone can explain the subtle(?) difference(s)?


// Comment out line 26
// Uncomment line 27 and 79

program Test;
{$i AeroLib/AeroLib.simba}
const
STATE_A = 1;
STATE_B = 2;

type
tPointer = record
isProc: Boolean;
proc: procedure;
func: function: Boolean;
name: String;
end;

exampleRecord = record
name: String;
uptext: TStringArray;
end;

var
ptr: tPointer;

exampleVar: exampleRecord = ['Bank chest we want to use', ['Bank', 'chest']];
//exampleVar: exampleRecord;

function testFunc(input: exampleRecord): Boolean;
begin
if waitUpTextMulti(input.uptext, 500) then
exit(True);
end;

function getState(): Integer;
begin
if testFunc(exampleVar) then
exit(STATE_A)
else
exit(STATE_B);
end;

procedure aLoop();
begin
writeln('a loop');
end;

procedure bLoop();
begin
writeln('b loop');
end;

procedure loop();
begin
with ptr do
begin
case getState() of
STATE_A:
begin
name := 'state a';
isProc := true;
proc := @aLoop;
func := nil;
end;
STATE_B:
begin
name := 'state b';
isProc := true;
proc := [MENTION=61374]bloop[/MENTION];
func := nil;
end;
end;
end;
end;

begin
initAL();

//exampleVar := ['Bank chest we want to use', ['Bank', 'chest']];

while True do
begin
loop();
with ptr do
begin
if isProc then
proc()
else
func();
end;
end else
begin
Wait(5000);
end;
end.


Brandon

2015-02-15 15:42:00

From: honeyhoney
…



Sorry but you're looking in the wrong part of your code. lol. It's sucks having to hear this, but this is another issue with Lape itself (because there should only be one way to initialise a structure).

This is not a problem with your initialisation or code.. really.. Well it is a problem with your code but it's not your fault. It's a problem with how you use the structure you have stored.. You are creating a copy every time you loop and so it access violates.. Why? I don't know..


Change:


function testFunc(input: exampleRecord): Boolean;

to:


function testFunc(var input: exampleRecord): Boolean;

Therefore this problem lies in the copying. Which technically should not be a problem.. but what's new right?


NOTE that you could also do:


function testFunc(input: ^exampleRecord): Boolean;

but that's more work.. If you want to copy it, then you need to copy the address OR increase the reference count..


ANOTHER fix is to do (which you've discovered already):


exampleVar: exampleRecord := ['Bank chest we want to use', ['Bank', 'chest']];

//instead of:

exampleVar: exampleRecord = ['Bank chest we want to use', ['Bank', 'chest']];

//Notice the assignment operator is different..


This one baffles me.. Not sure why we have two different ways of initialising a structure. I guess one is lazy initialisation but I'm not sure.. Either way, it's a common error.


Example SSCCE (Short Self-Contained Correct Example).. I removed dependencies just to show where the problem lies for anyone that just wants to test it:


const
STATE_A = 1;
STATE_B = 2;

type
tPointer = record
isProc: Boolean;
proc: procedure;
func: function: Boolean;
name: String;
end;

exampleRecord = record
name: String;
uptext: TStringArray;
end;

var
ptr: tPointer;
exampleVar: exampleRecord = ['Bank chest we want to use', ['Bank', 'chest']];

function testFunc(var input: exampleRecord): Boolean; //using var.. If you remove var, access violation due to copying.
begin
writeln(input.uptext);
end;

function getState(): Integer;
begin
if testFunc(exampleVar) then
exit(STATE_A)
else
exit(STATE_B);
end;

procedure aLoop();
begin
writeln('a loop');
end;

procedure bLoop();
begin
writeln('b loop');
end;

procedure loop();
begin
with ptr do
begin
case getState() of
STATE_A:
begin
name := 'state a';
isProc := true;
proc := @ aLoop;
func := nil;
end;
STATE_B:
begin
name := 'state b';
isProc := true;
proc := @ bloop;
func := nil;
end;
end;
end;
end;

begin
while True do
begin
loop();
with ptr do
begin
if isProc then
proc()
else
func();
end;
end else
begin
Wait(5000);
end;
end.


and this is the example SSCCE with the assignment operator being the only thing different:



const
STATE_A = 1;
STATE_B = 2;

type
tPointer = record
isProc: Boolean;
proc: procedure;
func: function: Boolean;
name: String;
end;

exampleRecord = record
name: String;
uptext: TStringArray;
end;

var
ptr: tPointer;
exampleVar: exampleRecord := ['Bank chest we want to use', ['Bank', 'chest']]; //Use := instead of =

function testFunc(input: exampleRecord): Boolean;
begin
writeln(input.uptext);
end;

function getState(): Integer;
begin
if testFunc(exampleVar) then
exit(STATE_A)
else
exit(STATE_B);
end;

procedure aLoop();
begin
writeln('a loop');
end;

procedure bLoop();
begin
writeln('b loop');
end;

procedure loop();
begin
with ptr do
begin
case getState() of
STATE_A:
begin
name := 'state a';
isProc := true;
proc := @ aLoop;
func := nil;
end;
STATE_B:
begin
name := 'state b';
isProc := true;
proc := @ bloop;
func := nil;
end;
end;
end;
end;

begin
while True do
begin
loop();
with ptr do
begin
if isProc then
proc()
else
func();
end;
end else
begin
Wait(5000);
end;
end.

honeyhoney

2015-02-15 18:28:45

Thank you so much for the detailed response!

I'm definitely going to have to take another look at your A lot About Lape.. thread.

You must spread some Reputation around before giving it to Brandon again.