User Tag List

Page 1 of 2 1 2 LastLast
Results 1 to 10 of 12

Thread: crashes inside ffasm.cpp when assigning script slots

  1. #1
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,114
    Mentioned
    41 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    10,521
    Level
    30
    vBActivity - Bars
    Lv. Percent
    46.91%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    34.14%

    crashes inside ffasm.cpp when assigning script slots

    Has anybody else experienced this? I am getting crashes even when compiling a blank buffer.

  2. #2
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,114
    Mentioned
    41 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    10,521
    Level
    30
    vBActivity - Bars
    Lv. Percent
    46.91%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    34.14%
    Ok, I investigated and there are two problems:

    1. Someone at some point increased the number of global scripts to 4 from 3, but didn't allocate space for the extra script in ZQuest; this was easily fixed.
    2. The default quest (qst.dat) is corrupt (!!!). It thinks that it contains 5 different global scripts: the first is ~Init (fine), but it also thinks that it contains "slot2_icecombos" and "GhostZHActiveScript" as well as a few more global scripts with corrupt names. It thinks these scripts are assigned to global slots 4+ which of course don't exist, and this is causing the crash.
    @Gleeok , @Saffith do you know what is going on? The qst.dat is one I pulled from the 2.50.2 Windows zip file. I checked the quest saving code and I do not see why it would have created this corruption; is it possible qst.dat was saved using some experimental build of ZQ with extra global slots (the old master, maybe) and accidentally included in 2.50.2?

    My main concern is that any new quest created in 2.50.2 and saved there will propagate the corruption...

  3. #3
    Is this the end?
    ZC Developer
    Saffith's Avatar
    Join Date
    Jan 2001
    Age
    34
    Posts
    3,289
    Mentioned
    140 Post(s)
    Tagged
    6 Thread(s)
    vBActivity - Stats
    Points
    5,828
    Level
    23
    vBActivity - Bars
    Lv. Percent
    67.24%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    4.97%
    I don't know how those extra scripts got there exactly, but they were removed for 2.50.3. I think those were entirely from qst.dat and weren't actually saved with the individual quests, since they're written in a for(int i=0; i<NUMSCRIPTGLOBAL; i++) loop. Loading an older quest in the current build, I don't see them.

    I wouldn't expect them to cause a crash, though, since global scripts are loaded into the array in a similarly limited loop.
    [téknolŕiz]

    ffcscript.zh 1.1.1 - Updated 2014-08-19
    ghost.zh 2.8.1 - Updated 2016-09-16
    tango.zh 1.2.0 - Updated 2016-09-16

  4. #4
    Mad, Mad, Author ZoriaRPG's Avatar
    Join Date
    Oct 2006
    Location
    Prydon Academy
    Posts
    757
    Mentioned
    67 Post(s)
    Tagged
    1 Thread(s)
    vBActivity - Stats
    Points
    2,912
    Level
    17
    vBActivity - Bars
    Lv. Percent
    50.71%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    24.42%
    Quote Originally Posted by DarkDragon View Post
    Has anybody else experienced this? I am getting crashes even when compiling a blank buffer.
    I have had no such crashes with any of the builds that I've done with the 2.54 stuff. Parser changes could certainly do that, though, in my experience.


    Script Headers: RPG.zh ( v. a0.97.1 ) ( RPG.zh Thread ) | stdArguments.zh (v.6.9.9/1) | | Timers.zh (v.1.5)
    ZScript | ZC Dev | ZC 2.53 | Alucard's: stdCombos.zh (v1.1) | stdWeapons.zh | particles.z
    All of the code that I create and publish here is free for use, modification and distribution under the GPL v2.0.

  5. #5
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,114
    Mentioned
    41 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    10,521
    Level
    30
    vBActivity - Bars
    Lv. Percent
    46.91%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    34.14%
    Quote Originally Posted by Saffith View Post
    I don't know how those extra scripts got there exactly, but they were removed for 2.50.3. I think those were entirely from qst.dat and weren't actually saved with the individual quests, since they're written in a for(int i=0; i<NUMSCRIPTGLOBAL; i++) loop. Loading an older quest in the current build, I don't see them.

    I wouldn't expect them to cause a crash, though, since global scripts are loaded into the array in a similarly limited loop.
    The writing code looks like: (zq_class.cpp starting at around line 10000)

    Code:
    word numglobalbindings=0;
            
            for(std::map<int, pair<string, string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
            {
                if(it->second.second != "")
                {
                    numglobalbindings++;
                }
            }
            
            if(!p_iputw(numglobalbindings, f))
            {
                new_return(2007);
            }
            
            for(std::map<int, pair<string, string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
            {
                if(it->second.second != "")
                {
                    if(!p_iputw(it->first,f))
                    {
                        new_return(2008);
                    }
                    
                    if(!p_iputl((long)it->second.second.size(), f))
                    {
                        new_return(2009);
                    }
                    
                    if(!pfwrite((void *)it->second.second.c_str(), (long)it->second.second.size(),f))
                    {
                        new_return(2010);
                    }
                }
            }
    and the quest load code
    Code:
    word numglobalbindings;
            p_igetw(&numglobalbindings, f, true);
            
            for(int i=0; i<numglobalbindings; i++)
            {
                word id;
                p_igetw(&id, f, true);
                p_igetl(&bufsize, f, true);
                buf = new char[bufsize+1];
                pfread(buf, bufsize, f, true);
                buf[bufsize]=0;
                
                //nothing needed here
                if(keepdata)
                {
                    //Disable old '~Continue's, they'd wreak havoc. Bit messy, apologies ~Joe
                    if(strcmp(buf,"~Continue") == 0)
                    {
                        globalmap[id].second = "";
                        
                        if(globalscripts[GLOBAL_SCRIPT_CONTINUE] != NULL)
                            globalscripts[GLOBAL_SCRIPT_CONTINUE][0].command = 0xFFFF;
                    }
                    else
                    {
                        globalmap[id].second = buf;
                    }
                }
                
                delete[] buf;
            }
    The crash occurs if id > 4, since the slot assignment code later on assumes that no script will try to be assigned to global slots > 3.

    Somehow qst.dat has corrupt bindings in it, and I don't see anything that will stop these corrupt bindings from being saved out again in new quests.

    The fix is not too difficult, and amounts to ignoring any global bindings with id > NUMSCRIPTGLOBAL at quest load time. But I'd like to know how the corruption got into qst.dat in the first place, to make sure it's not an ongoing bug...

  6. #6
    Mad, Mad, Author ZoriaRPG's Avatar
    Join Date
    Oct 2006
    Location
    Prydon Academy
    Posts
    757
    Mentioned
    67 Post(s)
    Tagged
    1 Thread(s)
    vBActivity - Stats
    Points
    2,912
    Level
    17
    vBActivity - Bars
    Lv. Percent
    50.71%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    24.42%
    Quote Originally Posted by DarkDragon View Post
    The writing code looks like: (zq_class.cpp starting at around line 10000)

    Code:
    word numglobalbindings=0;
            
            for(std::map<int, pair<string, string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
            {
                if(it->second.second != "")
                {
                    numglobalbindings++;
                }
            }
            
            if(!p_iputw(numglobalbindings, f))
            {
                new_return(2007);
            }
            
            for(std::map<int, pair<string, string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
            {
                if(it->second.second != "")
                {
                    if(!p_iputw(it->first,f))
                    {
                        new_return(2008);
                    }
                    
                    if(!p_iputl((long)it->second.second.size(), f))
                    {
                        new_return(2009);
                    }
                    
                    if(!pfwrite((void *)it->second.second.c_str(), (long)it->second.second.size(),f))
                    {
                        new_return(2010);
                    }
                }
            }
    and the quest load code
    Code:
    word numglobalbindings;
            p_igetw(&numglobalbindings, f, true);
            
            for(int i=0; i<numglobalbindings; i++)
            {
                word id;
                p_igetw(&id, f, true);
                p_igetl(&bufsize, f, true);
                buf = new char[bufsize+1];
                pfread(buf, bufsize, f, true);
                buf[bufsize]=0;
                
                //nothing needed here
                if(keepdata)
                {
                    //Disable old '~Continue's, they'd wreak havoc. Bit messy, apologies ~Joe
                    if(strcmp(buf,"~Continue") == 0)
                    {
                        globalmap[id].second = "";
                        
                        if(globalscripts[GLOBAL_SCRIPT_CONTINUE] != NULL)
                            globalscripts[GLOBAL_SCRIPT_CONTINUE][0].command = 0xFFFF;
                    }
                    else
                    {
                        globalmap[id].second = buf;
                    }
                }
                
                delete[] buf;
            }
    The crash occurs if id > 4, since the slot assignment code later on assumes that no script will try to be assigned to global slots > 3.

    Somehow qst.dat has corrupt bindings in it, and I don't see anything that will stop these corrupt bindings from being saved out again in new quests.

    The fix is not too difficult, and amounts to ignoring any global bindings with id > NUMSCRIPTGLOBAL at quest load time. But I'd like to know how the corruption got into qst.dat in the first place, to make sure it's not an ongoing bug...
    One thing that I can say with certainty, is that this has been in qst.dat since at least 2.50.1, if not 2.50.0RCs. It has never causes crashes on any of the released ZC builds, nor on 2.50.3RC1, nor 2.54. That doesn't mean we shouldn't fix it, and by this, I mean fix improper values called in the loops, but rather, that we also need to know why it was crashing whatever you just built.

    It doesn't crash the builds that I made from your tree.


    Script Headers: RPG.zh ( v. a0.97.1 ) ( RPG.zh Thread ) | stdArguments.zh (v.6.9.9/1) | | Timers.zh (v.1.5)
    ZScript | ZC Dev | ZC 2.53 | Alucard's: stdCombos.zh (v1.1) | stdWeapons.zh | particles.z
    All of the code that I create and publish here is free for use, modification and distribution under the GPL v2.0.

  7. #7
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,114
    Mentioned
    41 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    10,521
    Level
    30
    vBActivity - Bars
    Lv. Percent
    46.91%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    34.14%
    The crash occurs here:

    Code:
    for(std::map<int, pair<string,string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
                        {
                            if(it->second.second != "")
                            {
                                tempfile = fopen("tmp","w");
                                
                                if(!tempfile)
                                {
                                    jwin_alert("Error","Unable to create a temporary file in current directory!",NULL,NULL,"O&K",NULL,'k',0,lfont);
                                    return D_O_K;
                                }
                                
                                if(output)
                                {
                                    al_trace("\n");
                                    al_trace("%s",it->second.second.c_str());
                                    al_trace("\n");
                                }
                                
                                for(vector<Opcode *>::iterator line = scripts[it->second.second].begin(); line != scripts[it->second.second].end(); line++)
                                {
                                    string theline = (*line)->printLine();
                                    fwrite(theline.c_str(), sizeof(char), theline.size(),tempfile);
                                    
                                    if(output)
                                    {
                                        al_trace("%s",theline.c_str());
                                    }
                                }
                                
                                fclose(tempfile);
                                parse_script_file(&globalscripts[it->first],"tmp",false);
                            }
                            else if(globalscripts[it->first])
                            {
                                delete[] globalscripts[it->first];
                                globalscripts[it->first] = new ffscript[1];
                                globalscripts[it->first][0].command = 0xFFFF;
                            }
                        }
    What happens if it->first > 3? The following, none of which is good:
    - delete[] gets called on a random memory address that was not new[]ed'
    - the results of new ffscript[1]; get written into a random memory address.

    Your operating system is not required to kill your program when you write to a bad memory address; it can simply silently corrupt your data instead. If your program is not crashing, that is what's happening.

    For example, since the global script variables are allocated like

    Code:
    ffscript *globalscripts[NUMSCRIPTGLOBAL];
    ffscript *linkscripts[NUMSCRIPTLINK];
    it's likely that on your OS, the code is silently corrupting the linkscripts, instead of crashing.

  8. #8
    Is this the end?
    ZC Developer
    Saffith's Avatar
    Join Date
    Jan 2001
    Age
    34
    Posts
    3,289
    Mentioned
    140 Post(s)
    Tagged
    6 Thread(s)
    vBActivity - Stats
    Points
    5,828
    Level
    23
    vBActivity - Bars
    Lv. Percent
    67.24%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    4.97%
    Okay, I'm losing track of what's what here...
    The actual script data is in the array globalscripts. globalmap is a std::map<int, pair<string, string> >, which maps script numbers to their names and... It looks like first is just used to display "Slot #: " and such? That seems unnecessary. But yeah, at least the names are saved with the quest.
    I'm not seeing why id>3 would be a problem, though. It looks like that's only used for globalmap, and that should be harmless. If it were accessing globalscripts[id], that would be a problem, but I don't see that anywhere.
    [téknolŕiz]

    ffcscript.zh 1.1.1 - Updated 2014-08-19
    ghost.zh 2.8.1 - Updated 2016-09-16
    tango.zh 1.2.0 - Updated 2016-09-16

  9. #9
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,114
    Mentioned
    41 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    10,521
    Level
    30
    vBActivity - Bars
    Lv. Percent
    46.91%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    34.14%
    @Saffith Yes, the corruption is in the slot assignments, not in the ZASM buffers themselves.

    So the crash does not occur when you first load the quest, but rather, the next time you recompile the scripts. ZQuest does indeed write to globalscripts[id] at that time.

    (Also, the title of this thread is unintentionally confusing; the crash inside ffasm.cpp was due to a different bug, which I've already pushed a fix for. The crash I'm describing here occurs in zquest.cpp)

  10. #10
    Mad, Mad, Author ZoriaRPG's Avatar
    Join Date
    Oct 2006
    Location
    Prydon Academy
    Posts
    757
    Mentioned
    67 Post(s)
    Tagged
    1 Thread(s)
    vBActivity - Stats
    Points
    2,912
    Level
    17
    vBActivity - Bars
    Lv. Percent
    50.71%
    Daily Activity
    0%
    Weekly Activity
    3.83%
    Monthly Activity
    24.42%
    Quote Originally Posted by DarkDragon View Post
    The crash occurs here:

    Code:
    for(std::map<int, pair<string,string> >::iterator it = globalmap.begin(); it != globalmap.end(); it++)
                        {
                            if(it->second.second != "")
                            {
                                tempfile = fopen("tmp","w");
                                
                                if(!tempfile)
                                {
                                    jwin_alert("Error","Unable to create a temporary file in current directory!",NULL,NULL,"O&K",NULL,'k',0,lfont);
                                    return D_O_K;
                                }
                                
                                if(output)
                                {
                                    al_trace("\n");
                                    al_trace("%s",it->second.second.c_str());
                                    al_trace("\n");
                                }
                                
                                for(vector<Opcode *>::iterator line = scripts[it->second.second].begin(); line != scripts[it->second.second].end(); line++)
                                {
                                    string theline = (*line)->printLine();
                                    fwrite(theline.c_str(), sizeof(char), theline.size(),tempfile);
                                    
                                    if(output)
                                    {
                                        al_trace("%s",theline.c_str());
                                    }
                                }
                                
                                fclose(tempfile);
                                parse_script_file(&globalscripts[it->first],"tmp",false);
                            }
                            else if(globalscripts[it->first])
                            {
                                delete[] globalscripts[it->first];
                                globalscripts[it->first] = new ffscript[1];
                                globalscripts[it->first][0].command = 0xFFFF;
                            }
                        }
    What happens if it->first > 3? The following, none of which is good:
    - delete[] gets called on a random memory address that was not new[]ed'
    - the results of new ffscript[1]; get written into a random memory address.

    Your operating system is not required to kill your program when you write to a bad memory address; it can simply silently corrupt your data instead. If your program is not crashing, that is what's happening.

    For example, since the global script variables are allocated like

    Code:
    ffscript *globalscripts[NUMSCRIPTGLOBAL];
    ffscript *linkscripts[NUMSCRIPTLINK];
    it's likely that on your OS, the code is silently corrupting the linkscripts, instead of crashing.

    Gorgeous. That could in fact, explain some things that have occurred that I've never been able to explain. Absolutely gorgeous.


    Script Headers: RPG.zh ( v. a0.97.1 ) ( RPG.zh Thread ) | stdArguments.zh (v.6.9.9/1) | | Timers.zh (v.1.5)
    ZScript | ZC Dev | ZC 2.53 | Alucard's: stdCombos.zh (v1.1) | stdWeapons.zh | particles.z
    All of the code that I create and publish here is free for use, modification and distribution under the GPL v2.0.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
About us
Armageddon Games is a game development group founded in 1997. We are extremely passionate about our work and our inspirations are mostly drawn from games of the 8-bit and 16-bit era.
Social