08 Jan, 2013, Splork wrote in the 1st comment:
Votes: 0
I've come across a crash bug which has me baffled. The crash has happened twice in two weeks and is centered around updating the MSDP variable for Opponent_health.

The code is below and the debug info is further down in the post. The variables seem alright, except for hit_points giving some ordinarily large value Also, print out of the pOpponent values show all null yet p pOpponent gives a perfectly fine value. I am not even sure how this can happen?

Any advice?

The only thing we can think of is to add a check that pOpponent_health is less than 100 before sending and we arent even sure this is correct.

struct char_data *pOpponent = NULL;

// if (pOpponent != NULL)
if (ch->specials.fighting)
{
struct char_data *pOpponent = ch->specials.fighting;
int hit_points =
(GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, hit_points);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH_MAX, 100);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, GET_LEVEL (pOpponent));
MSDPSetString (d, eMSDP_OPPONENT_NAME, GET_NAME (pOpponent));
}
else // need to clear variables
{
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}
(gdb) bt
#0 0x08176868 in msdp_update () at comm.c:5642
#1 0x0816ac9b in game_loop () at comm.c:2132
#2 0x0816844b in run_the_game (port=6101) at comm.c:1312
#3 0x08168394 in main (argc=4, argv=0xbfd739e4) at comm.c:1176
(gdb) frame 0
#0 0x08176868 in msdp_update () at comm.c:5642
5642 (GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
(gdb) list
5637 // if (pOpponent != NULL)
5638 if (ch->specials.fighting)
5639 {
5640 struct char_data *pOpponent = ch->specials.fighting;
5641 int hit_points =
5642 (GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
5643 MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, hit_points);
5644 MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH_MAX, 100);
5645 MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, GET_LEVEL (pOpponent));
5646 MSDPSetString (d, eMSDP_OPPONENT_NAME, GET_NAME (pOpponent));
(gdb) p ch
$4 = (struct char_data *) 0x1e89c158
(gdb) p pOpponent
$5 = (struct char_data *) 0x11d754a8
(gdb) p hit_points
$6 = 1357671870
(gdb) p *pOpponent
$7 = {nr = 0, vnum = 0, in_room = 0, nbrain = 0, ntbrain = 0, brain = 0x0, tbrain = 0x0, func = 0, config = 0x0, mudl = 0x0, nconfig = 0, player = {
name = 0x0, short_descr = 0x0, long_descr = 0x0, description = 0x0, title = 0x0, godtitle = 0x0, bamfin = 0x0, bamfout = 0x0, gname = 0x0,
gtitle = 0x0, gt_noun = 0, gt_adj = 0, gt_sup = 0, gt_form = 0, sex = 0 '\000', class = "\000\000\000\000\000\000\000\000\000", race = 0 '\000',
level = '\000' <repeats 11 times>, hometown = 0, homezone = 0, talks_DEPRECATED = "\000\000", time = {birth = 0, logon = 0, last_rent = 0,
last_saved = 0, played = 0, poy_years = 0, age_rate = 0}, weight = 0, height = 0, worships = 0, beacon = 0, passage = 0, has_prayed = 0, sev = 0,
alias = 0x0, holy_item = 0x0, mimages = 0 '\000', servanthps = 0, stabticker = 0 '\000', tmp_equip = {0 <repeats 100 times>},
from_room_msg = '\000' <repeats 127 times>, prompt = '\000' <repeats 255 times>, kill_history = 0x0, housing = 0x0}, mob_data = {home = 0,
home_zone = 0, help = {0, 0, 0, 0, 0}, hates = {0, 0, 0, 0, 0}, mobwait = 0, height_weight = 0, species = 0, max_hit = 0, hit = 0, treasure = 0x0,
trigtraps = 0x0, quest = 0x0, queststage = 0x0, questgoal = 0x0, n_thoughts = 0, thoughts = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
n_innate_effects = 0, innate_apply = {0 <repeats 20 times>}, innate_modifier = {0 <repeats 20 times>}, personality_bitv = {0}, xp_multiplier = 0},
abilities = {str = 0 '\000', str_add = 0 '\000', intel = 0 '\000', wis = 0 '\000', dex = 0 '\000', con = 0 '\000', charisma = 0 '\000',
futurestat1 = 0 '\000', futurestat2 = 0 '\000', futurestat3 = 0 '\000'}, tmpabilities = {str = 0 '\000', str_add = 0 '\000', intel = 0 '\000',
wis = 0 '\000', dex = 0 '\000', con = 0 '\000', charisma = 0 '\000', futurestat1 = 0 '\000', futurestat2 = 0 '\000', futurestat3 = 0 '\000'},
capabilities = {str_cap_bonus = 0 '\000', intel_cap_bonus = 0 '\000', wis_cap_bonus = 0 '\000', dex_cap_bonus = 0 '\000', con_cap_bonus = 0 '\000'},
points = {mana = 0, max_mana = 0, gain_mana = 0, hit = 0, max_hit = 0, gain_hit = 0, move = 0, max_move = 0, gain_move = 0, armor = 0, gold = 0,
bank = 0, balance = 0, max_balance = 0, val = {0, 0, 0}, exp = 0, hitroll_DEPRECATED = 0 '\000', damroll_DEPRECATED = 0 '\000', death_ticker = 0,
current_quest_DEPRECATED = 0, quests_DEPRECATED = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, tquest_DEPRECATED = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, range_bot = 0,
range_top = 0, freeze = 0, office = 0, wizify = 0}, specials = {fighting = 0x0, mfighting = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
hunting = 0x0, riding = 0x0, ridden = 0x0, p_from = 0x0, p_to = 0x0, charging = 0x0, protected_by = 0x0, combat_state = 0 '\000', affected_by = 0,
affected2_by = 0, position = 0 '\000', default_pos = 0 '\000', act = 0, act2 = 0, player_act = 0, player_act2 = 0,
spells_to_learn_DEPRECATED = 0 '\000', carry_weight = 0, carry_items = 0 '\000', timer = 0, was_in_room = 0, load_room = 0, apply_saving_throw = {0, 0,
0, 0, 0}, conditions = "\000\000", adef = {{n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0,
attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0,
n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0,
attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0, n_sides = 0, bonus = 0, attack_type = 0}, {n_dice = 0,
n_sides = 0, bonus = 0, attack_type = 0}}, n_attacks = 0, last_direction = 0 '\000', alignment = 0, wizinvis = 0, holyLite = 0, wizlock = 0,
memory = {count = 0, spells = {0, 0, 0, 0, 0, 0, 0, 0}}, last_mv = 0 '\000'}, skills = 0x0, chaosd = {tot_kills = 0, kill_points = 0}, affected = 0x0,
imbued = 0x0, equipment = {0x0 <repeats 100 times>}, visited = 0x0, carrying = 0x0, studying = 0x0, desc = 0x0, next_in_room = 0x0, next = 0x0,
next_fighting = 0x0, followers = 0x0, master = 0x0, spirits = 0x0, spirit_master = 0x0, watching = 0x0, pissed = 0x0, annoyed = 0x0, grappling = 0x0,
grappled_by = 0x0, singing_for = 0x0, song_victims = 0x0, song_casters = 0x0, warcry_leader = 0x0, smooped_by = 0x0, sac_totals = {active = 0,
number = 0, number_pc = 0, level = 0, align = 0, max_align = 0, min_align = 0, gold = 0, min_level = 0}, shift_eq = 0x0, ptest_eq = 0x0, path = 0x0,
charge_dir = 0, catch = 0x0, extras = {0, 0, 0, 0, 0}, txtlines = 0, colors = '\000' <repeats 24 times>, kickdam = 0, damroll = 0, hitroll = 0, exp2 = 0,
honor = 0, channel = 0, rlist = {{name = 0x0}, {name = 0x0}, {name = 0x0}, {name = 0x0}, {name = 0x0}, {name = 0x0}}, squelch = {{name = 0x0}, {
name = 0x0}, {name = 0x0}, {name = 0x0}, {name = 0x0}, {name = 0x0}}, uid = 0, initial_gold = 0, replay = 0x0, n_replay = 0, phase_offset = 0,
pc_stats = 0x0, hdb_index = 0, next_talk_pulse = 0, move_in_progress = 0, orig_max_hits = 0}
(gdb)
08 Jan, 2013, Davion wrote in the 2nd comment:
Votes: 0
it looks like pOpponent is being recycled and the variable isn't being nulled. Does slothmud free data or store it in a free list to avoid allocations later? Possibly a dead opponent?
08 Jan, 2013, Splork wrote in the 3rd comment:
Votes: 0
I'm not sure if this will solve it but we will give it a try since something with pOpponent is getting messed up.
if (ch->specials.fighting)
{
struct char_data *pOpponent = ch->specials.fighting;

if (pOpponent != NULL)
{
int hit_points = (GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, hit_points);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH_MAX, 100);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, GET_LEVEL (pOpponent));
MSDPSetString (d, eMSDP_OPPONENT_NAME, GET_NAME (pOpponent));
} else {
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}
}
else // need to clear variables
{
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}
09 Jan, 2013, mangan wrote in the 4th comment:
Votes: 0
Matter of opinion, but I feel that your original code looked cleaner in some regards. In the new attempt, it seems that you have some dead code, since your inner else block will never be executed. (If something is non-null, you assign a pointer to that non-null value, so that value cannot be null… thus a redundant if check.)


Splork said:
The variables seem alright, except for hit_points giving some ordinarily large value Also, print out of the pOpponent values show all null yet p pOpponent gives a perfectly fine value.


Via the code shown and debug output, I would assume the crash is coming from the divide by zero (since GET_MAX_HIT(pOpponent) is returning 0). The variable hit_points would be a garbage value, since it hasn't been assigned yet. It holds data for whatever was at that memory location before.

Based on the gdb output, my reaction was the same as Devion's. Looks like someone has died, or something has caused the char_data to be set to 0. Hard to tell without knowing more about your codebase.

For a temporary fix, I'd do something like:
struct char_data *pOpponent = ch->specials.fighting;
if (pOpponent && GET_MAX_HIT (pOpponent))
{
int hit_points = (GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, hit_points);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH_MAX, 100);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, GET_LEVEL (pOpponent));
MSDPSetString (d, eMSDP_OPPONENT_NAME, GET_NAME (pOpponent));
}
else // need to clear variables
{
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}


Alternatively, you could do something like this to assist debugging:
struct char_data *pOpponent = ch->specials.fighting;
if (pOpponent)
{
if (GET_MAX_HIT (pOpponent))
{
int hit_points = (GET_HIT (pOpponent) * 100) / GET_MAX_HIT (pOpponent);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, hit_points);
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH_MAX, 100);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, GET_LEVEL (pOpponent));
MSDPSetString (d, eMSDP_OPPONENT_NAME, GET_NAME (pOpponent));
}

else
{
// INSERT DEBUG STATEMENTS HERE TO LOG THE ISSUE TO ASSIST TRACKING IT DOWN ONLINE
// …
// Now we need to clean it up as if there wasn't a pOpponent
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}
}
else // need to clear variables
{
MSDPSetNumber (d, eMSDP_OPPONENT_HEALTH, 0);
MSDPSetNumber (d, eMSDP_OPPONENT_LEVEL, 0);
MSDPSetString (d, eMSDP_OPPONENT_NAME, "");
}


In general I'd hate the code duplication for clearing variables, but assuming you find the bug quickly, it can be taken out at that time. (Not worth a special refactor at this point, imho.)

Hth
09 Jan, 2013, Davion wrote in the 5th comment:
Votes: 0
The main problem here is it looks like it's not the MSDP implementation. You may have a deeply rooted bug here. The problem is ch->specials.fighting is not NULL but the values are. The entire range has been deliberately set to zero somewhere. It shows strings in p *pOpponent that repeat \0. This means you're most likely using one of the built-in methods for zeroing a pointer to a struct. I believe they are static automatic variables, using calloc to allocate fresh memory, and using memset to set a range to 0.

What Mangan suggested should stop your crashes and assuming you take advice on adding logs to help locate this bug, could possibly eliminate other problems.
09 Jan, 2013, Telgar wrote in the 6th comment:
Votes: 0
Your opponent isn't fighting anyone:

specials = {fighting = 0x0,

Some game mechanics have stopped the fight (mob or player fled, summoned, recalled, died, unconscious..) and not cleared the fighting pointer for both parties.
09 Jan, 2013, Splork wrote in the 7th comment:
Votes: 0
I took Mangan's advice and hopefully this will help us track it down.

We also moved msdp_update to above perform_violence in the game loop, previously it was the last call ( a Kavir suggestion ).

Thanks for the help and I will update the thread once I know something!
0.0/7