Array access out of bounds(Hideous Destructor minimod)

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Array access out of bounds(Hideous Destructor minimod)

Postby Silentdarkness12 » Sun Nov 17, 2019 2:57 pm

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 allExpand view
aaa.RandomContents();


Code: Select allExpand view
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 allExpand view
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 allExpand view
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 allExpand view
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.
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby Cherno » Sun Nov 17, 2019 4:49 pm

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 allExpand view
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 allExpand view
if(invclasses.size() == 0)
{
     return;
}
for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...


In your line

Code: Select allExpand view
let wep=(class<hdweapon>)(invclasses[thisitem]);


"thisitem" has a value outside the array's bounds.
User avatar
Cherno
 
Joined: 06 Dec 2016

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

Postby Silentdarkness12 » Sun Nov 17, 2019 5:08 pm

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 allExpand view
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 allExpand view
if(invclasses.size() == 0)
{
     return;
}
for(int i=0;i<5;i++){
         int thisitem=random(1,invclasses.size())-1;
...


In your line

Code: Select allExpand view
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.
Attachments
ZSCRIPT.txt
(23.18 KiB) Downloaded 3 times
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby Cherno » Sun Nov 17, 2019 5:29 pm

Code: Select allExpand view
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;
...
User avatar
Cherno
 
Joined: 06 Dec 2016

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

Postby Silentdarkness12 » Sun Nov 17, 2019 5:58 pm

Cherno wrote:
Code: Select allExpand view
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.
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby Cherno » Sun Nov 17, 2019 7:02 pm

Which is line 664 in backpack.zs?
User avatar
Cherno
 
Joined: 06 Dec 2016

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

Postby Silentdarkness12 » Sun Nov 17, 2019 7:04 pm

Cherno wrote:Which is line 664 in backpack.zs?


Code: Select allExpand view
let wep=(class<hdweapon>)(invclasses[thisitem]);
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby Cherno » Sun Nov 17, 2019 8:12 pm

Sorry, I can't help you.
User avatar
Cherno
 
Joined: 06 Dec 2016

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

Postby Silentdarkness12 » Sun Nov 17, 2019 8:33 pm

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.

Attachments
HDGearCrate.wad
(25.38 KiB) Downloaded 3 times
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby Graf Zahl » Mon Nov 18, 2019 1:35 am

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.
User avatar
Graf Zahl
Lead GZDoom Developer
Lead GZDoom Developer
 
Joined: 19 Jul 2003
Location: Germany

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

Postby Silentdarkness12 » Mon Nov 18, 2019 9:31 am

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 allExpand view
if(wep.owner && wep)wep=HDWeapon(owner.dropinventory(wep));
User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride

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

Postby _mental_ » Mon Nov 18, 2019 9:40 am

You need to check wep for null first, and then you can check wep.owner.
Code: Select allExpand view
if (wep && wep.owner) // ...
_mental_
 
 
 
Joined: 07 Aug 2011

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

Postby Silentdarkness12 » Mon Nov 18, 2019 9:54 am

_mental_ wrote:You need to check wep for null first, and then you can check wep.owner.
Code: Select allExpand view
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.

User avatar
Silentdarkness12
Level 7: ZScript Victim
 
Joined: 15 Aug 2013
Location: Plains of Pride


Return to Scripting

Who is online

Users browsing this forum: No registered users and 1 guest