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.
Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Suspicion:
Too many ACS functions / compiler bug / memory leak / voodoo?
Environment:
Spoiler:
Windows 7x64
SLADE 3.1.12
GZDoom Builder 2.3.0.3107 (3f8da3f) (tested with Ultimate Doom Builder, same thing)
ACC 1.57 Win Version (copied to GZDoom Builder Compilers as well)
Background:
I've been working on a rouglike Doom Mod for about two years now, which grew in complexity with time, to a point it's a little bit... unstable right now. I'm working in both ZScript and ACS, but the main bulk of it is written in ACS, compiled in SLADE and imported as a library into a map like this:
Recently I've hit some problems with reaching the max limit of map variables (128), but that was optimized and solved - using a custom getter / setter (mimicking a dictionary-type variable, so it's more compact), but that didn't cause any issues from what I could see. The thing that did on the other hand.
Then, some time later my SLADE ACS compiler threw an error of "too many functions", so I've solved it by updating my ACC to 1.57 (Windows version).
Right now I'm working with one library, that's also the main core of this mod. It's 14000 lines long (less than that in reality, some of that is just formatting), with about 257 functions. The thing I've noticed (after making a post about "too many functions" compiler error), that even if the compiler does it's job without any errors, the game violently crashes as soon as this library is imported if there's more than 257 functions. Even a simple function without any content will totally crash it if it's over 257.
Compiler output with no game crashes:
Spoiler:
=== Log: ===
Host byte order: LITTLE endian"C:\Users\Black\AppData\Roaming\SLADE3\temp\DIAC.acs": 14053 lines (1599 included) 257 functions 100 scripts 97 closed 1 respawn 1 death 1 enter 22 global variables 0 world variables 115 map variables 8 global arrays 0 world arrays object "C:\Users\Black\AppData\Roaming\SLADE3\temp\DIAC.o": 132860 bytes
=== Error log: ===
Original ACC Version 1.10 by Ben Gokey
Copyright (c) 1995 Raven Software, Corp.
This is version 1.56 (Dec 27 2018)
This software is not supported by Raven Software or Activision
ZDoom changes and language extensions by Randy Heit
Further changes by Brad Carney
Even more changes by James Bentler
Some additions by Michael "Necromage" Weber
Error reporting improvements and limit expansion by Ty Halderman
Include paths added by Pascal vd Heiden
Compiler output causing the violent crash:
Spoiler:
=== Log: ===
Host byte order: LITTLE endian"C:\Users\Black\AppData\Roaming\SLADE3\temp\DIAC.acs": 14053 lines (1599 included) 258 functions 100 scripts 97 closed 1 respawn 1 death 1 enter 22 global variables 0 world variables 115 map variables 8 global arrays 0 world arrays object "C:\Users\Black\AppData\Roaming\SLADE3\temp\DIAC.o": 132888 bytes
=== Error log: ===
Original ACC Version 1.10 by Ben Gokey
Copyright (c) 1995 Raven Software, Corp.
This is version 1.56 (Dec 27 2018)
This software is not supported by Raven Software or Activision
ZDoom changes and language extensions by Randy Heit
Further changes by Brad Carney
Even more changes by James Bentler
Some additions by Michael "Necromage" Weber
Error reporting improvements and limit expansion by Ty Halderman
Include paths added by Pascal vd Heiden
So, here I am, again - lost, dazed and confused, but never giving up. If anybody would have any kind of input, please share your knowledge or suspicions!
Thanks for your time.
_mental_ wrote:Please post a minimal sample to crash GZDoom.
With pleasure, but I don't really understand what a "minimal sample" would be in that case?
Also, what can I do for sure is to post a link to a crash report zip: https://we.tl/t-RWbv1Kzq4i
_mental_ wrote:Please post a minimal sample to crash GZDoom.
I'd love to, but don't really understand what are you asking of me. Is it the full crash report? Because there's nothing specific I can extract from the code that crashes the game. The only thing I do is to add a function, doesn't matter how complex (it could even be empty) anywhere in the library - and boom - crash.
What I've just tested is I've made a simple pk3 with 300 functions in it, and it worked just fine, so I doubt it's the function limit at play here.
I also noticed just now, by moving stuff around, that one of my functions that I've added today just fired up for no reason! Nothing even is using it, and yet, I can see it logging it's messages (via log(s:"checking")) in the log box as the game starts.
The function is:
OS: Windows 7 (NT 6.1) Build 7601
S
M_LoadDefaults: Load system defaults.
Using program directory for storage
W_Init: Init WADfiles.
. .. blah blah blah...
No bots.cfg, so no bots
----------------------------------------
MAPUPGR - LIMBO
Unknown bottom texture 'WALL_WAT' on first side of linedef 2807
Unknown middle texture 'DOSWALL' on first side of linedef 2833
Warning: z-offsetting not allowed for interactive portals. Changing line 2057 to teleport-portal!
Warning: z-offsetting not allowed for interactive portals. Changing line 2214 to teleport-portal!
checking
challange failed!
So this uses the function even if it's not called for and super-crashes. But, funny thing - there is a point in the code where I can insert this function and it DOESN'T crash, but the function... does nothing. No logging, no actions, doesn't return anything. Trying to pinpoint the exact placement of crash / no crash at this moment, but it's going to take a while...
A minimal sample is a small mod which contains only needed assets to reproduce a crash.
To debug an issue, we need something to work with. We cannot read your mind in order to replicate exactly the same conditions that lead to a crash.
_mental_ wrote:A minimal sample is a small mod which contains only needed assets to reproduce a crash.
To debug an issue, we need something to work with. We cannot read your mind in order to replicate exactly the same conditions that lead to a crash.
Thanks for the explanation, I was afraid that was the case.
Trust me, if I only knew what piece of code breaks it all, I'd gladly isolate it and send it over for analysis, but the problem is - it's a huge piece of interconnected scripts and functions, and adding a single empty function seems to be the case now. So sadly I can't just send an empty dummy function and point my finger to it. It almost seems like a heisenbug. And sending over the whole mod? I doubt anybody would want to go through it all, right?
Anyway, I've cut down as much content as possible in a short time, left it with only two maps - it happens on map MAPUGRD, using library called DIAC. If you find this function (aptly named crasher() around line 986), you'll see my observations / comments from when I was trying to debug this thing. Sorry for this format, but really, cutting this down to a single function or a shorter snippet won't work, as it only happens when this much is in the file.
_mental_ wrote:Could you please explain in simple straightforward steps how to reproduce the crash?
Of course, my mistake by not doing it earlier.
1. Only this pk3 and wad files are needed + Doom2.wad as an iwad.
2. Start a new game -> Doom Infinite -> Normal Difficulty
3. First map is mostly for setup, there's a teleport behind the door to the second map.
4. Second map crashes GZDoom on start, displaying a function output (log) that's not even used anywhere.
With a little more tinkering and testing it really seems that going over 257 functions in this particular ACS file breaks something: if a function (the 257th one) is declared immediately after the ENTER script, it crashes the game. If it's declared at the bottom of the file, it's totally ignored (no crashes, but no output and doesn't even do anything).
Hope someone can understand this issue, thanks for your time!
Just take a look at this line. Function number is stored in one byte, i.e. we can address only 256 different functions.
Higher bits of an integer are simply ignored, so call to a function with index 256 becomes a call to a function with index zero.
Apparently, the change is wrong, and it should be reverted.
Because of the way ACS interpreter is written, the crash isn't so easy to fix.
Addition of all necessary checks is rather tedious task, and moreover, they will slow down execution.
This is huge, I thought I was going insane over here, thinking it really is 8192 functions max, and as the ACC compiler didn't throw an error I assumed it's something else.
I assume I should now optimize the code for less functions and the change will be reverted in the next ACC update.
Yes, you should either split code onto several modules, or switch to ZScript and use ACS only when it makes sense.
Anyway, I made this pull request to restore correct limit on number of function.
That doesn't really help. The problem goes deeper. In uncompacted code the larger function limit can be used but in compacted code, which is the default somebody was shaving off too much size again for no gain, the last time I found a place like this I had to add a new PCode to handle the overflow case, the same should be done here.
I have zero interest in extending ACS. The initial contributor didn't make it properly, and such "fix" will be much more sophisticated that the contribution itself.
My intention is to fix broken code generation only. Here is my solution for this issue.