Page 1 of 1

Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 2:57 pm
by Silentdarkness12
I've been working on a minimod for Hideous Destructor to add a sort of gear crate that you can lug around to help carry all the stuff around between levels you could ever need, and even stuff you don't need. However, i'm now running into a problem that is significantly well above and beyond what I can make sense of, and especially baffling since i'm heavily copying the backpack code for this, and yet i'm running into a problem here I don't run into with the HD backpack.


Code: Select all

aaa.RandomContents();

Code: Select all

let wep=(class<hdweapon>)(invclasses[thisitem]);
Somehow, these bits of codes are colliding and making an array access out of bounds, whatever that is. I seriously got nothing here, and I need help figuring this one out. Entire blocks of relevant code included below for the sake of being more reasonable.

HDGearcrate.wad

Code: Select all

extend class HDGearCrate{
	void RandomContents(){
		if(hd_debug)A_Log("\n*  Backpack:  *");
		for(int i=0;i<5;i++){
			int thisitem=random(1,invclasses.size())-1;
			let wep=(class<hdweapon>)(invclasses[thisitem]);
			let pkup=(class<hdpickup>)(invclasses[thisitem]);
			let mag=(class<hdmagammo>)(pkup);
			int howmany=0;
			if(wep){
				let iii=inventory(spawn(wep,pos,ALLOW_REPLACE));
				if(hdweapongiver(iii))itemtobackpack(hdweapongiver(iii).actualweapon);
				else if(hdpickupgiver(iii))itemtobackpack(hdpickupgiver(iii).actualitem);
				else itemtobackpack(iii);
			}else if(mag){
				howmany=min(
					random(1,random(1,20)),
					getdefaultbytype(mag).maxamount,
					HDCONST_BPMAX/(
						max(1.,getdefaultbytype(mag).roundbulk)
						*max(1.,getdefaultbytype(mag).magbulk)
						*5.
					)
				);
				for(int j=0;j<howmany;j++){
					inventory iii=inventory(spawn(mag,pos,ALLOW_REPLACE));
					if(iii){
						itemtobackpack(iii);
						if(iii)iii.destroy();
					}
				}
			}else if(pkup){
				let iii=spawn(pkup,pos,ALLOW_REPLACE);
				if(iii){
					iii.destroy();
					howmany=min(
						random(1,getdefaultbytype(pkup).bmultipickup?random(1,80):random(1,random(1,20))),
						getdefaultbytype(pkup).maxamount,
						HDCONST_BPMAX/(max(1.,getdefaultbytype(pkup).bulk)*5.)
					);
					if(
						getdefaultbytype(pkup).refid==""
					){
						howmany=random(-2,howmany);
					}
					amounts[thisitem]=""..howmany;
					if(amounts[thisitem].toint()<1)amounts[thisitem]="";
				}
			}
			if(hd_debug)A_Log(invclasses[thisitem].."  "..howmany);
		}
		weaponbulk();
		updatemessage(index);
	}
	}

Code: Select all

class WildGearCrate:IdleDummy {
		//$Category "Items/Hideous Destructor/Gear"
		//$Title "Backpack (Random Spawn)"
		//$Sprite "GRCRA0"
	override void postbeginplay(){
		super.postbeginplay();
		let aaa=HDBackpack(spawn("HDGearCrate",pos,ALLOW_REPLACE));
		aaa.RandomContents();
		destroy();
	}
}
Hideous_Destructor_Master

Code: Select all

extend class HDBackpack{
	void RandomContents(){
		if(hd_debug)A_Log("\n*  Backpack:  *");
		for(int i=0;i<5;i++){
			int thisitem=random(1,invclasses.size())-1;
			let wep=(class<hdweapon>)(invclasses[thisitem]);
			let pkup=(class<hdpickup>)(invclasses[thisitem]);
			let mag=(class<hdmagammo>)(pkup);
			int howmany=0;
			if(wep){
				let iii=inventory(spawn(wep,pos,ALLOW_REPLACE));
				if(hdweapongiver(iii))itemtobackpack(hdweapongiver(iii).actualweapon);
				else if(hdpickupgiver(iii))itemtobackpack(hdpickupgiver(iii).actualitem);
				else itemtobackpack(iii);
			}else if(mag){
				howmany=min(
					random(1,random(1,20)),
					getdefaultbytype(mag).maxamount,
					HDCONST_BPMAX/(
						max(1.,getdefaultbytype(mag).roundbulk)
						*max(1.,getdefaultbytype(mag).magbulk)
						*5.
					)
				);
				for(int j=0;j<howmany;j++){
					inventory iii=inventory(spawn(mag,pos,ALLOW_REPLACE));
					if(iii){
						itemtobackpack(iii);
						if(iii)iii.destroy();
					}
				}
			}else if(pkup){
				let iii=spawn(pkup,pos,ALLOW_REPLACE);
				if(iii){
					iii.destroy();
					howmany=min(
						random(1,getdefaultbytype(pkup).bmultipickup?random(1,80):random(1,random(1,20))),
						getdefaultbytype(pkup).maxamount,
						HDCONST_BPMAX/(max(1.,getdefaultbytype(pkup).bulk)*5.)
					);
					if(
						getdefaultbytype(pkup).refid==""
					){
						howmany=random(-2,howmany);
					}
					amounts[thisitem]=""..howmany;
					if(amounts[thisitem].toint()<1)amounts[thisitem]="";
				}
			}
			if(hd_debug)A_Log(invclasses[thisitem].."  "..howmany);
		}
		weaponbulk();
		updatemessage(index);
	}
I understand it's something to do with arrays, but I have not even the slightest bit of a clue what i'm doing wrong here. Help would be appreciated.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 4:49 pm
by Cherno
An out of bounds error means that you are trying to access an index that is beyond the size of the array. So, if you array has a Size of 3 (indices 0,1,2), then you can't access anything below 0 or anything above 2. Note that arrays always start at index 0. When trying to find a random index of on array, the most common error is to assume that the array will always have at least a Size of 1, and make 0 the minimum random value. However, if the array has a Size of 0, there isn't even an index of 0 so this will already result in an out of bounds error.

I understand that you copied this bit of code from the master:

Code: Select all

int thisitem=random(1,invclasses.size())-1;
One way to ensure an out of bounds error is avoided at all times is to check if the resulting index value is inside the array's bounds by adding a check like

Code: Select all

if(invclasses.size() == 0)
{
     return;
}
for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...
In your line

Code: Select all

let wep=(class<hdweapon>)(invclasses[thisitem]);
"thisitem" has a value outside the array's bounds.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 5:08 pm
by Silentdarkness12
Cherno wrote:An out of bounds error means that you are trying to access an index that is beyond the size of the array. So, if you array has a Size of 3 (indices 0,1,2), then you can't access anything below 0 or anything above 2. Note that arrays always start at index 0. When trying to find a random index of on array, the most common error is to assume that the array will always have at least a Size of 1, and make 0 the minimum random value. However, if the array has a Size of 0, there isn't even an index of 0 so this will already result in an out of bounds error.

I understand that you copied this bit of code from the master:

Code: Select all

int thisitem=random(1,invclasses.size())-1;
One way to ensure an out of bounds error is avoided at all times is to check if the resulting index value is inside the array's bounds by adding a check like

Code: Select all

if(invclasses.size() == 0)
{
     return;
}
for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...
In your line

Code: Select all

let wep=(class<hdweapon>)(invclasses[thisitem]);
"thisitem" has a value outside the array's bounds.
Where should I put this? It's not clear, and when I tried to wing it, GZDoom pitched a fit at me. Full zscript file attatched if you wanna see the whole thing.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 5:29 pm
by Cherno

Code: Select all

extend class HDGearCrate{
   void RandomContents(){
      if(hd_debug)A_Log("\n*  Backpack:  *");
      if(invclasses.size() == 0)
{
     return;
}
      for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 5:58 pm
by Silentdarkness12
Cherno wrote:

Code: Select all

extend class HDGearCrate{
   void RandomContents(){
      if(hd_debug)A_Log("\n*  Backpack:  *");
      if(invclasses.size() == 0)
{
     return;
}
      for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...
Unfortunately, I got the same message. That didn't fix it.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 7:02 pm
by Cherno
Which is line 664 in backpack.zs?

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 7:04 pm
by Silentdarkness12
Cherno wrote:Which is line 664 in backpack.zs?

Code: Select all

let wep=(class<hdweapon>)(invclasses[thisitem]);

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 8:12 pm
by Cherno
Sorry, I can't help you.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Sun Nov 17, 2019 8:33 pm
by Silentdarkness12
Anyone else, i'm rather desperate.

Update: It turns out that updating HDGearCrate to come from HDWeapon instead of HDBackpack made it so that spawning the gear crate works, by itself, but putting something inside of it makes it shit out completely and give a different VM abort. WildGearCrate is what should be getting called, as it is what will make gear crates spawn on maps. I'll put up the new message and the wad, in case anyone wants to look deeper into it and see what I messed up.


Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Mon Nov 18, 2019 1:35 am
by Graf Zahl
There's a null pointer check missing. Execution can reach line 432 while wep is null, and then it aborts because you only check for wep.owner but not for wep itself.

Also, spaces are your friend! That code contains no spacing between tokens which makes it extremely hard to read.

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Mon Nov 18, 2019 9:31 am
by Silentdarkness12
Graf Zahl wrote:There's a null pointer check missing. Execution can reach line 432 while wep is null, and then it aborts because you only check for wep.owner but not for wep itself.

Also, spaces are your friend! That code contains no spacing between tokens which makes it extremely hard to read.
I am trying to keep the spacing a little bit intact for now, since i'm basing this heavily on Hideous Destructor's backpack code.

I tried this, but it still didn't work.

Code: Select all

if(wep.owner && wep)wep=HDWeapon(owner.dropinventory(wep));

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Mon Nov 18, 2019 9:40 am
by _mental_
You need to check wep for null first, and then you can check wep.owner.

Code: Select all

if (wep && wep.owner) // ...

Re: Array access out of bounds(Hideous Destructor minimod)

Posted: Mon Nov 18, 2019 9:54 am
by Silentdarkness12
_mental_ wrote:You need to check wep for null first, and then you can check wep.owner.

Code: Select all

if (wep && wep.owner) // ...
I fixed that one,but i'm back to having a problem with RandomContents() call in HD's backpack.zs now, where that's causing a rather pervasive read from address zero.

Actually, I found the problem with help from HD discord. The problem is that i'm trying to cast to HDBackpack, which it doesn't inheirit from. Switching cast to GearCrate fixed the thing and it works now.

EDIT: No it doesn't. Testing it and another showed itself. Something is wrong with the ItemToBackpack function, but the line it's called from isn't saying anything remotely meaningful.