BUG: Object not in managed pool. [AGS 3.1.2] [VERIFIED - PENDING FIX]

Started by monkey0506, Thu 19/03/2009 07:34:54

Previous topic - Next topic

monkey0506

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. I've uploaded it for reference.

Here's all relevant code. Don't say I didn't warn you.

Code: ags
#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. :=

Pumaman

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.

monkey0506

Thanks so much Chris for determining where this error was coming from. I was sure I wasn't doing anything wrong. :=

SMF spam blocked by CleanTalk