ID:1623236
 
(See the best response by GhostAnime.)
Code:
#define DEBUG
world/fps = 100

proc/let( t, pos )
return ascii2text( text2ascii(t,pos) )

#define TEXT 1
#define INTEGER 2
#define SYMBOL 4

proc/randString( length = 5 , flags = TEXT|INTEGER )

var/static/l[] = list(65,90,97,122,48,57,33,47,162,254)

var/g[0]
if(flags & TEXT) g.Add(1,3)
if(flags & INTEGER) g.Add(5)
if(flags & SYMBOL) g.Add(7,9)

for(var/i=1 to length)
var/x = pick(g)
. += ascii2text(rand(l[x],l[x+1]))

string
var
value
length

proc
set_value(v)
value = v
length = length(v)

compare(string/s)
for(var/n=1 to s.length)
.+=let(s.value,n)==let(value,n)
./=s.length

generate(length,flags=1)
set_value(randString(length,flags))

breed(string/s)
for(var/n=1 to length)
var/g = s.value
if(prob(50))
g = value
.+=let(g,n)
var/string/r = new
r.set_value(.)
return r

client/verb/test(t as text)
var
string
s = new
s2 = new
cs

s.set_value(ckey(t))
s2.generate(s.length)

do
var/string/s3 = new
s3.generate(s.length)
s3 = s3.breed(s2)
var/c = s.compare(s3)
if(c>cs)
cs = c
s2=s3
src << output(null,"output1")
src << "([cs]) [s2.value]"
sleep(0)
while(cs<1)
world << "done"


Problem description:
At random iterations in the loop during test(), I'm getting an index out of bound runtime pointing to the line 'var/x = pick(g)' in randString. I have no clue what's causing this error. Any ideas?

Best response
I tried testing but did not run in to the error nor can I see any reason for it to happen.

Was there a particular string you entered that caused this error to appear?

I recommend logging each critical step and go through it when you encounter the error:
client/verb/test(t as text)
#ifdef DEBUG // If DEBUG is not defined, this is not done
world.log = file("debug_header.txt") // Save the information sent here.
world.log << "Encrypting [t]"
#endif

var
string
s = new
s2 = new
cs

s.set_value(ckey(t))
s2.generate(s.length)

do
var/string/s3 = new
s3.generate(s.length)
s3 = s3.breed(s2)
var/c = s.compare(s3)
if(c>cs)
cs = c
s2=s3
src << output(null,"output1")
src << "([cs]) [s2.value]"
#ifdef DEBUG
world.log = file("debug_header.txt") // Reset file location as it may be different from another proc.
world.log << "Encrypting [t]"
#endif

sleep(-1)
while(cs<1)
world << "done"

#ifdef DEBUG
world.log = null // Stop writing to the log
fdel("debug_header.txt") // Delete the logfile. If not null'd earlier, the file is protected due to being in use
#endif



proc/randString( length = 5 , flags = TEXT|INTEGER )

var/static/l[] = list(65,90,97,122,48,57,33,47,162,254)

var/g[0]
if(flags & TEXT) g.Add(1,3)
if(flags & INTEGER) g.Add(5)
if(flags & SYMBOL) g.Add(7,9)

#ifdef DEBUG
world.log = file("debug_randString.txt")
world.log << "Length = [length]"
world.log << "Flags = [flags]"
world.log << "g = [list2params(g)]"
#endif

for(var/i=1 to length)
#ifdef DEBUG
world.log << "\n\n============= i = [i] =============\n"
#endif
var/x = pick(g)
#ifdef DEBUG
world.log << "x = [x]"
#endif
. += ascii2text(rand(l[x],l[x+1]))
#ifdef DEBUG
world.log << "\n. = [.]\n================================\n"
#endif


#ifdef DEBUG
world.log = null // Stop writing to the logfile
fdel("debug_randString.txt")// Delete the log file since we know no error occured (otherwise this part would not happen
#endif


If the error occurs, the file should remain and you can look at the last entry. Obviously you do not need to define #ifdef DEBUG if you do not want to.
The list index out of bounds error means that you are trying to access an item of an index that doesn't exist. For example, if the length of the list is 3 and you try to access list[4] you will get an error.

I'm guessing that somewhere the length of the list is being changed, so the fixed length argument is not reliable enough.

What you need to do is change this: for(var/i=1 to length) to this: for(var/i=1 to length(l)), that way you know that the loop always knows what length the list is.

Actually the list might not contain anything at all in some cases, so you might want to have if(length(g)) or if(length(l)) in there.
Have you tried it with longer strings? There wasn't any particular string that did it but the longer ones should provide more of an opportunity for it to show itself. Try 'helloeveryoneitsme'.

And cheers, I'll try that debug approach and get back.
Multiverse, I know what the error means. The issue is it's occuring over a call to pick(). length is not the length of a list, in this case it is a constant value. It's always going to equal the length of the string which was input into test(). Maybe you should actually read what the proc is doing before commenting.
Actually, forget what I said. This should fix it:
if(length(g))
for(var/i=1 to length)
var/x = pick(g)
while(pick(g) > length(l))
x = pick(g)
. += ascii2text(rand(l[x],l[x+1]))

If the number picked from list g is greater than the length of list l, that you are accessing, then it will cause an error.
did you even read what I said? the issue has nothing to do with the length var or l. it's pointing towards 'x=pick(g)'. Besides, the way the proc works and is being called, l[x] and l[x+1] will always be in bounds.
If you say the issue is x=pick(g), then where else do you expect to find the problem? You need to investigate list g.

if(!istype(g, /list))
world << "g is not a list!"

if(!length(g))
world << "g is empty!"

for(var/x in g)
if(!isnum(x))
world << "g contains an item that is not a number!"
break

If you get no output from this, then it means that x=pick(g) is not the problem.
I just updated to 506.1247 and it seems to have stopped happening.