Okay, the code is rather long so let me explain what I'm doing. I'm creating a generic vectorized stack which can have any type of data pushed into it. What's happening is that my game is crashing with this
run-time error:
Quote---------------------------
Adventure Game Studio
---------------------------
An internal error has occurred. Please note down the following information.
If the problem persists, post the details on the AGS Technical Forum.
(ACI version 3.12.1074)
Error: Error running function 'game_start':
Error: Pointer cast failure: the object being pointed to is not in the managed object pool
---------------------------
OK
---------------------------
No CrashInfo.dmp is generated by this error, but it is completely fatal. The offending line is this:
data[i] = mystack.Pop();
In which data is a dynamic String array and Stack::Pop returns a String. The problem only seems to occur within a while loop and assigning the data from Stack::Pop directly into a String. Each line independently (i.e., just calling the function, or just setting the String to a string-literal) works normally as expected.
Here is the source (http://monkey.05.06.googlepages.com/Stack_CRASH.rar). I've uploaded it for reference.
Here's all relevant code. Don't say I didn't warn you.
#define StackData String
String StringMergeArray(String array[], String glue) {
if ((array == null) || (String.IsNullOrEmpty(array[0])) || (array[0].AsInt <= 0)) return null;
if (glue == null) glue = "";
String buffer = "";
int i = 1;
int size = array[0].AsInt;
while (i <= size) {
buffer = buffer.Append(array[i]);
if (i < size) buffer = buffer.Append(glue);
i++;
}
return buffer;
}
String[] SplitByString(this String*, String otherString) {
String s[];
int i = this.IndexOf(otherString);
if ((String.IsNullOrEmpty(otherString)) || (i == -1)) {
s = new String[2];
s[0] = "1";
s[1] = this;
return s;
}
s = new String[this.Length + 1];
String buffer = this;
int lineCount = 0;
while (i != -1) {
lineCount++;
s[lineCount] = buffer.Substring(0, i);
i += otherString.Length;
if (i < buffer.Length) {
buffer = buffer.Substring(i, buffer.Length);
i = buffer.IndexOf(otherString);
}
else i = -1;
}
lineCount++;
s[lineCount] = buffer;
String t[] = new String[lineCount + 1];
i = 1;
while (i <= lineCount) {
t[i] = s[i];
i++;
}
t[0] = String.Format("%d", lineCount);
return t;
}
enum StackPopType {
eStackPopFirstInFirstOut,
eStackPopFirstInLastOut,
eStackPopRandom
};
struct Stack {
StackPopType PopType;
protected StackData Data;
writeprotected int ItemCount;
int MaxItems;
import StackData Pop(bool remove=true, int index=SCR_NO_VALUE);
// ... and so forth
};
String StackDataDelimiter;
StackData Stack::Pop(bool remove, int index) {
if (index == SCR_NO_VALUE) {
if (this.PopType == eStackPopFirstInFirstOut) index = 0;
else if (this.PopType == eStackPopFirstInLastOut) index = (this.ItemCount - 1);
else if (this.PopType == eStackPopRandom) index = Random(this.ItemCount - 1);
}
if ((index < 0) || (index >= this.ItemCount) || (!this.ItemCount) ||
(StackData.IsNullOrEmpty(this.Data))) return null;
StackData items[] = this.Data.SplitByString(StackDataDelimiter);
int size = items[0].AsInt;
if (index >= size) return null;
StackData data = items[index + 1];
if (remove) {
this.ItemCount--;
if ((!this.ItemCount) || (size == 1)) {
this.Data = null;
return data;
}
StackData buffer[] = new StackData[size];
int i = 1;
while (i < size) {
if (i <= index) buffer[i] = items[i];
else buffer[i] = items[i + 1];
i++;
}
buffer[0] = StackData.Format("%d", size - 1);
items = buffer;
}
this.Data = StringMergeArray(items, StackDataDelimiter);
return data;
}
function game_start() {
StackDataDelimiter = "**STACKDATA**";
Stack mystack;
mystack.MaxItems = 100;
mystack.Push(Stack.IntToData(381));
mystack.Push(Stack.StringToData("hello world"));
mystack.Push(Stack.StringToData("goodbye."));
mystack.PopType = eStackPopRandom;
StackData data[] = new StackData[mystack.ItemCount];
int i = 0;
int size = mystack.ItemCount;
while (i < size) {
data[i] = mystack.Pop(); // CRASH!
// data[i] = "anything else"; // no crash
// mystack.Pop(); // no crash
i++;
}
}
If I'm being daft in any way, please someone point it out to me so I can slap myself. Thanks. :=
Interesting, thanks for reporting this.
It looks like a bug in the script compiler if you have a local dynamic array variable within a function, and attempt to return one of its elements as the return value from the function.
In this case, in your Stack::Pop function it does a "return data;" and data is one of the elements of the items[] local variable.
As a workaround, add this line before both the "return data;" commands in Stack::Pop:
items = null;
that will force the array to be freed first and prevent it from incorrectly freeing the array element that you're trying to return.
I'll look into a fix for a future version.
Thanks so much Chris for determining where this error was coming from. I was sure I wasn't doing anything wrong. :=