Rathena: Mapserver crash caused by RA_CLUSTERBOMB and SR_CRESCENTELBOW (damage overflow (?))

Created on 1 Jul 2018  路  3Comments  路  Source: rathena/rathena

  • rAthena Hash: e7fd6aa5bdfac454996c0c1bc720c7cf02022a36
  • Client Date: 2015-11-04 RE
  • Server Mode: Renewal
  • Description of Issue:

    • Result: The usage of SR_CRESCENTELBOW vs RA_CLUSTERBOMB detonated using RA_DETONATOR causing mapserver to crash.
    • How to Reproduce:

      • Ranger A Place Cluster Bomb

      • Sura B Use Crescent Elbow but don't trigger the bomb, just right beside the blast area

      • Ranger A detontate placed trap using Detonator

    • Official Information: I don't know
  • Modifications that may affect results:

    • I'm implementing Gray Wing Boots ( https://www.divine-pride.net/database/item/22172 ) that greatly increase RA_CLUSTERBOMB damage (more than 400%)
    • For normal test, you can just use bonus2 bSkillAtk,"RA_CLUSTERBOMB",800;
  • GDB's bt full stack:
    ```(gdb) bt full

    0 0x000056535700fbff in skill_detonator (bl=0x7f441ef427c4, ap=) at skill.cpp:17319

    unit_id = 217
    ap = <optimized out>
    bl = 0x7f441ef427c4
    

    1 0x0000565356f53e90 in map_foreachinareaV (func=0x56535700faf0 ,

    y0=, x1=, y1=, type=64, ap=, wall_check=false) at map.cpp:764
    bx =
    by =
    cx = 1511447936
    cy = 22099
    returnCount = 0
    bl =
    blockcount =
    i = 0
    ap_copy = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7ffd6df818e0, reg_save_area = 0x7ffd6df81810}}

    2 0x0000565356f54083 in map_foreachinallarea (func=func@entry=0x56535700faf0 ,

    x0=, y0=, x1=, y1=, type=64) at map.cpp:780
    returnCount = 0
    ap = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7ffd6df818d8, reg_save_area = 0x7ffd6df81810}}

    3 0x0000565357045928 in skill_castend_pos2 (src=src@entry=0x565360d4bff0, x=161, y=185, skill_id=2237, skill_lv=1, tick=tick@entry=3531793441, flag=0)

    at skill.cpp:12163
    sd = 0x565360d4bff0
    sc =
    sce = 0x0
    sg =
    type =
    i =
    __FUNCTION__ = "skill_castend_pos2"

    4 0x00005653570483d5 in skill_castend_pos (tid=tid@entry=-1, tick=tick@entry=3531793441, id=, data=data@entry=0) at skill.cpp:11559

    maxcount = <optimized out>
    src = 0x565360d4bff0
    sd = <optimized out>
    ud = 0x565360d4c010
    md = 0x0
    

    y0=, x1=, y1=, type=64, ap=, wall_check=false) at map.cpp:764
    bx =
    by =
    cx = 1511447936
    cy = 22099
    returnCount = 0
    bl =
    blockcount =
    i = 0
    ap_copy = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7ffd6df818e0, reg_save_area = 0x7ffd6df81810}}

    2 0x0000565356f54083 in map_foreachinallarea (func=func@entry=0x56535700faf0 ,

    x0=, y0=, x1=, y1=, type=64) at map.cpp:780
    returnCount = 0
    ap = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7ffd6df818d8, reg_save_area = 0x7ffd6df81810}}

    3 0x0000565357045928 in skill_castend_pos2 (src=src@entry=0x565360d4bff0, x=161, y=185, skill_id=2237, skill_lv=1, tick=tick@entry=3531793441, flag=0)

    at skill.cpp:12163
    sd = 0x565360d4bff0
    sc =
    sce = 0x0
    sg =
    type =
    i =
    __FUNCTION__ = "skill_castend_pos2"

    4 0x00005653570483d5 in skill_castend_pos (tid=tid@entry=-1, tick=tick@entry=3531793441, id=, data=data@entry=0) at skill.cpp:11559

    maxcount = <optimized out>
    src = 0x565360d4bff0
    sd = <optimized out>
    ud = 0x565360d4c010
    md = 0x0
    __FUNCTION__ = "skill_castend_pos"
    

    5 0x000056535708b186 in unit_skilluse_pos2 (src=src@entry=0x565360d4bff0, skill_x=skill_x@entry=161, skill_y=skill_y@entry=185,

    skill_id=skill_id@entry=2237, skill_lv=skill_lv@entry=1, casttime=0, castcancel=0) at unit.cpp:2117
    sd = 0x565360d4bff0
    ud =
    sc =
    bl = {next = 0x565360d4bff0, prev = 0x56535701acf0 , id = 1844976352, m = 171, x = 161,
    y = 185, type = BL_NUL}
    tick = 3531793441
    range =
    __FUNCTION__ = "unit_skilluse_pos2"

    6 0x000056535708b274 in unit_skilluse_pos (src=0x565360d4bff0, skill_x=, skill_y=, skill_id=2237, skill_lv=)

    at unit.cpp:1959
    No locals.

    7 0x0000565356f1645d in clif_parse_UseSkillToPos (fd=, sd=) at clif.cpp:12334

No locals.

8 0x0000565356eff544 in clif_parse (fd=) at clif.cpp:20401

    cmd = <optimized out>
    packet_len = 10
    sd = <optimized out>
    pnum = 0
    cmd2 = 1844976544

9 0x0000565356e9ca65 in do_sockets (next=) at socket.cpp:917

    rfd = {fds_bits = {256, 0 <repeats 15 times>}}
    timeout = {tv_sec = 0, tv_usec = 14584}

---Type to continue, or q to quit---
ret = 0
i = 8

10 main (argc=, argv=) at core.cpp:368

```

skill prerenewal renewal low bug

Most helpful comment

--- a/src/map/skill.cpp
+++ b/src/map/skill.cpp
@@ -17282,6 +17282,8 @@ int skill_detonator(struct block_list *bl, va_list ap)
                    map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);
                    break;
            }
+           if (!unit->group)
+               return 0;
            clif_changetraplook(bl, UNT_USED_TRAPS);
            unit->group->unit_id = UNT_USED_TRAPS;
            unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) +

As a temporary hot fix you could add that check. When the map_foreachinrange is calling skill_trap_splash. It's dealing the damage and then returns out of there and we have already verified unit->group from before but now after the damage has been dealt and the caster is dead, that assertion is failing because it is null now.

All 3 comments

Update
On continued testing, it only crashes when the player is in @duel mode.

Here's what i assume :
when Ranger A placing traps, and the damage got reflected by crescent elbow, the Ranger dies at the same time the traps removed (because of detonator), that's why on this line unit->group->unit_id = UNT_USED_TRAPS; the unit->group is nullptr because when player dies, he/she will automatically leaves @duel mode.

--- a/src/map/skill.cpp
+++ b/src/map/skill.cpp
@@ -17282,6 +17282,8 @@ int skill_detonator(struct block_list *bl, va_list ap)
                    map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);
                    break;
            }
+           if (!unit->group)
+               return 0;
            clif_changetraplook(bl, UNT_USED_TRAPS);
            unit->group->unit_id = UNT_USED_TRAPS;
            unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) +

As a temporary hot fix you could add that check. When the map_foreachinrange is calling skill_trap_splash. It's dealing the damage and then returns out of there and we have already verified unit->group from before but now after the damage has been dealt and the caster is dead, that assertion is failing because it is null now.

@aleos89 i've tested your hotfix and it worked on my test server. I will update this comment if there's an update on my live server.

Thanks a lot.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Surefirer picture Surefirer  路  3Comments

BrOgBr picture BrOgBr  路  3Comments

RadianFord picture RadianFord  路  3Comments

secretdataz picture secretdataz  路  4Comments

LiMoon picture LiMoon  路  4Comments