Carpet

Carpet

2M Downloads

Constant damage results in crash if taking damage fast-forwards the game.

James103 opened this issue ยท 2 comments

commented

To reproduce:

  1. Place a repeating command block with the command summon minecraft:falling_block ~ ~10 ~ {BlockState:{Name:"minecraft:anvil"},Time:1}.
  2. Place a stone pressure plate on the command block.
  3. Run the following command: /script run __on_player_takes_damage(player, amount, source, source_entity) -> (modify(player, 'effect', 'hunger', floor(2*amount), 199); modify(player, 'effect', 'resistance', floor(20*amount)); loop(floor(20*amount),game_tick());)
  4. Step on the pressure plate.
  5. Crash.

Also reproducible with lava and to a lesser extent cactus and some mobs.

Last four crashes:
crash-2020-05-22_19.25.26-server.txt
crash-2020-05-22_19.42.10-server.txt
crash-2020-05-22_19.43.11-server.txt
crash-2020-05-22_19.43.44-server.txt

Most likely cause:

  1. Taking damage calls the __on_player_takes_damage handler.
  2. The __on_player_takes_damage handler is set to call the game_tick() function a bunch of times.
  3. During one of the subsequent game_tick() calls, the player gets damaged again.
  4. Repeat steps 1 through 3 until a java.lang.StackOverflowError is triggered.
  5. This then results in a bunch of ... HERE>> game_tick() ... and Callback failed messages and eventually a crash.
commented

In that case, isn't it semi-intended, if it's a StackOverflowError, as it's an intended error?

And btw (out of curiosity) , what sort of crazy testing do you do to discover these bugs man?

commented

well, you are promising to handle player taking damage event and while handling it, you are causing the game to tick potentially catching the same event while still handling the previous event. Its a typical stack overflow causer. Make sure to release handling of the event before ticking the world, of if you are not sure it won't be handling itself, continue execution with schedule or task, like

__handle_damage(args) -> 
(
   do_somethings();
   game_tick(50);
   do_something_else();
)

__handle_safer(args) ->
(
   do_something();
   schedule(0, 'do_something_else', args);
)

With your setup of receiving constant damage, you may still run over your system infinitely, but at least it wouldn't keep adding layers to the stack.