I know there are a lot of questions on that famous "Segmentation fault core dump", but for what I can see, C/C++ is involved in most of them. But my issue is specific to a bash script, so I am trying my luck here.
I am running a simulator script (400+ lines so I cannot show you the code, can I ?) which sets and calculates a fight between two characters using dices and a profile (like you would do in a Dungeons and Dragons tabletop RPG). I have a reinitialisation function to reset the fight from scratch so that it can start a new one when there is a winner. At the end of the X rounds, some values from it are displayed (% hit, %block %hp per round, etc).
If I set 1, 50 or 100 rounds (100 fights), it's okay, it runs perfectly. But over 130~ fights, all of sudden, it displays without any lag or other complications the "Segmentation fault (core dumped)" message.
I have a general idea of what it is, but I cannot explain why it happens, I cannot resolve it, and I do not know what to do, or what to look for.
Some notes I can say after browsing a lot of topics :
There is no import, no based command system, no sed, awk, no array, no "complicated" command. I am just playing with variables (integer). No string. The most "complexe" command (to get a random number) is probably
(echo $((1 + RANDOM % 20)))
All my conditions are like this
if [[ "$Skill_Block2" == "Yes" ]];
then
With double bracket and variable between double quote (forgetting double quoted variable inside conditions could lead to problem, I heard).
There is no && or || or -a or -o (I also read that using direct "if" statement would be better)
The whole script is built around functions (easier to modify / implement). A function to calculate the damage is called by a function which check if a character can dodge the successful attack, which has been landed by another function allowing the success or the failure of that attack. Etc. I don't know if it is a good way of developping, but it "worked" so far.
I have accents and French characters, but they seem to be well managed by my OS version (Ubuntu).
I echo pretty much every single resolution so I can track mistakes. Perhaps displaying so much text is eating my virtual memory ? But I would never expect that on a Linux, to be honest.
I don't think I have infinite loops since I can run it 50++ times without any problem in the exact same order.
To display the stats, I am using a dirty way (I think) :
touch statistique.txt
echo "#|Player 1|Player 2" > statistique.txt
echo "ATT OK|$Number_Touch_OK1|$Number_Touch_OK1" >> statistique.txt
echo "ATT Failed|$Number_Hit_Failed1|$Number_Hit_Failed2" >> statistique.txt
echo "DEF Tried |$Number_Dodge_Tried1|$Number_Dodge_Tried2" >> statistique.txt
[...]
echo "Victory Number|$Victory1|$Victory2" >> statistique.txt
echo " "
column statistique.txt -t -s "|"
I tought about EOF, but I was not sure the variables would be interpreted. But at least I have a nicely formated text.
My Ubuntu is run on my Windows. Might be the problem ?
So here I am. I feel confused, and I am not very enthusiastic about posting this message as a wall of text without any code because it's too long (but if someone is brave enough, I can share the code, no problem). I have seen too few message about memory leak on bash, so... I cannot imagine a Linux OS running out of memory If you have any idea, advice, software (I tried Valgrind, but again, I am not sure it works with a bash script), please let me know.
EDIT : here's the file (solveur.sh) : https://github.com/IlliciteS/script
As pointed out in the comments, your program recurses endlessly. As each level of recursion consumes more memory, bash runs into the segmentation fault. Here's a minimal script to reproduce the problem (wrapped inside bash -c
so that your interactive shell doesn't crash):
$ bash -c 'f() { f; }; f'
Segmentation fault (core dumped)
You can prevent the segfault by limiting the maximum recursion level using bash's FUNCNEST
variable. However, this will only abort a bit more gracefully. To solve the actual problem you have to rewrite your script.
To identify the problem, You can look at the call graph of your script:
Every cycle inside this graph could max out the call stack. A bit of recursion is ok. But for your task, loops seem to be more natural anyway. I would start by using a loop to start new fights. Delete Relance_Match()
and change your main "method" to
for ((i=0; i<Nombre_Match_Total; i++)); do
Who_start_fight
echo "..."
Reinitialisation_Carac_New_Match
done
echo "..."
Statistique
You can drastically simplify your script with arrays. Right now, each player has its own set of variables and code fragments, e.g
# for player one
Victoire1=0
Touch1() {
# lots of code using <insertThingHere>1, e.g.
((Victoire1++))
}
# for player two
Victoire2=0
Touch2() {
# the same code as in Touch1, but with <insertThingHere>2 instead, e.g.
((Victoire2++))
}
With arrays this could be simplified to
Victoire=(0 0)
Touch() {
player=$1
# lots of code using <insertThingHere>[player], e.g.
((Victoire[player]++));
}