Trying to write past end of string (SOLV--erm...BROKEN)

Started by monkey0506, Tue 12/07/2005 21:23:26

Previous topic - Next topic

monkey0506

This code won't work with the way AGS currently works...

I had a crazy idea recently to try writing a function to write a string to a sub-string within a char array.  Basically I have a large array, and versus typing the same code over and over to find the starting point of, and then storing all 30 strings (it's inside of a struct), I wanted to do something like:

Code: ags
void StrCopyToCharArray(string text, string char_array, int start_index, int length, int array_size) {
  readonly int EOS = array_size - 1;
  if (start_index < 0) start_index = 0;
  else if (start_index > EOS) start_index = EOS;
  if (!StrLen(text)) {
    if (length < 0) {
      int end = start_index + length;
      if (end < 0) end = 0;
      while (start_index >= end) {
        StrSetCharAt(char_array, start_index, 0);
        start_index--;
        }
      }
    else {
      if (length == 0) length = EOS - start_index;
      int end = start_index + length;
      if (end > EOS) end = EOS;
      while (start_index <= end) {
        StrSetCharAt(char_array, start_index, 0);
        start_index++;
        }
      }
    return;
    }
  if (length < 0) {
    int end = start_index + length;
    if (end < 0) end = 0;
    int tindex = 0;
    while (start_index >= end) {
      StrSetCharAt(char_array, start_index, StrGetCharAt(text, tindex));
      tindex++;
      start_index--;
      }
    }
  else {
    if (length == 0) length = EOS - start_index;
    int end = start_index + length;
    if (end > EOS) end = EOS;
    int tindex = 0;
    while (start_index <= end) {
      Display("tindex: %d", tindex);
      StrSetCharAt(char_array, start_index, StrGetCharAt(text, tindex));
      tindex++;
      start_index++;
      }
    }
  }

char char_array[6000];

void game_start() {
  StrCopyToCharArray("this is some text.", char_array, 0, 199, 6000);
  }


Don't ask why I used void as the return type for game_start...it's just for testing anyway.  And so is the char array that I created here.  I'm just testing the function now...

Basically the problem is that every time I run the function it crashes the game with the error message:

Quote---------------------------
Adventure Game Studio
---------------------------
An error has occured. Please contact the game author for support, as this
is likely to be a scripting error and not a bug in AGS.
(ACI version 2.70.861)

in StrAdditions (line 374)
from StrAdditions (line 384)

Error: StrSetCharAt: tried to write past end of string

---------------------------
OK   
---------------------------

I've been using Display messages to sort out where the errors were coming from (this isn't the first error out of this code)...and as you can see, I've left one Display message in.

Since I put it in a loop, I get several messages displayed (telling me the value of tindex before trying to store the next character.  Output is displayed from "tindex: 0" through "tindex: 19".  Since the length of "this is some text." is 18 characters, I presumed that this may have something to do with it.

In fact, I just added two more characters and it now produces output through "tindex: 21".  So it definitely has something to do with the string TEXT, but I don't see what as I'm not changing the characters in that string.  Any help in solving this problem would be greatly appreciated.

I tried adding some lines:

Code: ags
/* in game_start */
StrCopyToCharArray("this will go first.", char_array, 0, 199, 6000);
  Display(char_array);


Now "this will go first." is displayed, but it's still crashing on the second statement:

Code: ags
StrCopyToCharArray("this is some text...", char_array, 200, 199, 6000);


This isn't fair!  I have to go...  Thanks for any help!

Gilbert

Since there is a limit to string length (200 something characters), the problem is probably caused by those:

StrSetCharAt(char_array, start_index, blah);

lines.
Though char_array was defined as an array of characters, it's used as a string in the function and in StrSetCharAt(), so to avoid people doing silly thing, it's quite understandable that something like below would possibly be checked and produce a crash:

StrSetCharAt(char_array, 300, 'T');

monkey0506

Understandable...but the crash occurs only when I pass anything greater than 0 as start_index.  Even if I pass length as 10, it crashes if start_index is greater than 0.  And it doesn't crash immediately if start_index is greater than 0.  It crashes after storing the entire string text (when it should start storing null values).  I haven't tried passing a string TEXT that is greater than start_index + length.

Okay, I just tested it, and that doesn't work.  So the function fails (crashes the game) if BOTH of the following are true:

1.  START_INDEX is greater than 0.
2.  TEXT is stored into CHAR_ARRAY entirely.

I guess I could always just do this the hard way.  It's okay.

Actually I can create a more customized function easily...I was just looking to provide a new function for my StrAdditions module.

Gilbert

It's possibly not the length of the TEXT, it may be related to that int LENGTH variable that you always like to pass 199 or more to it. Judging from your code, the number of loops executed does not depend on the provided text's length, but on the length variable alone, so for a line like this:

StrSetCharAt(char_array, start_index, StrGetCharAt(text, tindex));

your game will definitely crash if either:
1. start_index>200 something, or
2. tindex exceeds length of text

Since you pass numbers like 199 to length, condition 2 will occur.

monkey0506

Uh...I've passed something as short as 10 to length, and it still screwed up if start_index wasn't 0.  I'm 100% certain that it has to do with text.  I've done extensive testing...even if it may not sound like it...

Gilbert

#5
Okay, I've just checked and I think I've found the problem now.

The main problem is, you're trying to write a sequence of characters with value 0.

In an AGS string, whenever you set a character to 0, the string is shortened to that 0's position, the length of it is automagically updated.

So if you want to terminate a string, one 0 is enough.

Take the following example:
StrCopy(text, "123456789");
StrSetCharAt(text, 5, 0); //becomes "12345"
StrSetCharAt(text, 6, 0);

The game will crash when the 3rd line is executed, since after the second line, the length of text had been shortened to 5, so any attempt to change the character at position 6 or higher will generate a crash.

Look at your function, when "text" is empty it will write a sequence of 0's, if "text" is not empty, when tindex had gone past the length of text StrGetCharAT() will return 0 (not crashing, see manual).

That also means your idea probably won't work anyway, since when you set a character of a string to 0, it's shortened and the remaining characters are automatically discarded. For your array of 6000 crazy entries, the result is unpredictable (since the string functions were only designed for 200 something characters), that when you set say, character #190 to 0, you'll expect #191 thru 200 something to be discarded, but it's unsure what would happen to the remaining 200 something thru 6000th entries.

monkey0506

Okay, that makes sense.  But that doesn't explain why it crashes if start_index is greater than 0.  Also is there any way to clear a character to nothing in char_array without truncating the string?

Gilbert

I'm currently too lazy to check the code for the problem, however, why not try using a display in the loop and see if it's really related to the reason I posted about? Something like:
Display("%d %d", start_index, StrLen(char_array));
maybe somehow it DOES write past the string's end?

Quote from: monkey_05_06 on Wed 13/07/2005 15:39:12
Also is there any way to clear a character to nothing in char_array without truncating the string?

If you declare that parameter as a string in the function and you use string functions on it you can't. You can modify individual characters in any way you want if you manipulate it as an ordinary character array. However, I'm not quite sure if currently AGS supports arrays as function parameters, also I don't know in that case will the function modify a local copy of it only, or directly modify the original like for strings.

monkey0506

Okay...well, I guess that this function isn't going to work.  As previously mentioned, I have a customized workaround.  I was just trying to provide a global method.

Thanks for the help Gilbot.

SMF spam blocked by CleanTalk