Wesnoth segfault with [transform_unit]

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
Post Reply
User avatar
WhiteWolf
Forum Moderator
Posts: 769
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Wesnoth segfault with [transform_unit]

Post by WhiteWolf »

The original post is a little bit too cluttered, much better issue description in this reply.

______________________

Hello,

I'm having a bit of a headache with [transform_unit]. I'm trying to create a weapon special with some random effects, one if which is to transform the enemy unit to something if the attacker hits. However, certain unit types make Wesnoth crash to desktop with a segmentation fault.
Unit types that work fine for example: Yeti, Walking Corpse, or even custom units from the campaign such as a Pig.
Causes crash: Giant Rat. Or custom units too, such as my campaign's Rabbit.
Here is the code:
Code:
After some careful "printf-message" see how far it goes tactics, it appears that the attacker hits event runs to the end fine, I tried to show that in the code with a comment.
While that message is shown, I can see the newly transformed unit on the map, even if it's a Giant Rat or Rabbit. So the transformation is actually completed. But after I click away that last message, it's a CTD.

If I include an attack end event right after this attacker hits event - that won't fire, the code doesn't get that far before the CTD. So the crash happens before we get to any attack end events.

Now, I do have a lot of other attacker hits events from special effects and junk like that. It could be a conflict with those? I disabled most of these, at least the ones that are easily disabled - and it didn't solve anything, at least we know it's not one of those effects.
I'm asking for help, because it's maybe something obvious that I'm missing. Otherwise I guess I'll have to dig deeper into every other "attack end" event that my game has, and see in exactly which one the segfault happens. But before that, if someone spots the obvious reason, that'd be appreciated. :)
However, I was under the impression that Wesnoth should never segfault, no matter how rogue of an event I write, so... I really fail to see what's going on here.

My Wesnoth version is 1.14.5 (this is still the newest for this Debian distribution)
Last edited by WhiteWolf on May 28th, 2020, 3:44 pm, edited 1 time in total.
Main UMC campaigns: The Ravagers - now for 1.16, with new bugs!
Old UMC works: The Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
newfrenchy83
Code Contributor
Posts: 172
Joined: October 6th, 2017, 12:57 pm

Re: Wesnoth segfault with [transform_unit]

Post by newfrenchy83 »

i don't certain of thhis, but i think what modify an unit type in middle of fight and the weapon used in fight must cause the crash, probably because conflict with old value in begun of fight, and value after attacker hit event. use transform_unit, it is like if unit advance before the end of fight.
User avatar
WhiteWolf
Forum Moderator
Posts: 769
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Wesnoth segfault with [transform_unit]

Post by WhiteWolf »

I'm not sure I entirely understand.
I am using [transform_unit] to transform the unit. (The modify unit tag is only there, after the transform unit, in the case where the new unit is a Rabbit, to change it to a random variation.)
But it crashes in case of a Giant rat as well, in which case the [if]'s only lead to

Code: Select all

[transform_unit]
	id=$second_unit.id
	transform_to="$target_type"
[/transform_unit]
where $target_type is "Giant Rat".

I think I can imagine how transforming a unit in the middle of a fight can cause a conflict, but shouldn't the attack be just cancelled if one of the units is destroyed/modified in an event? Also, then why does it work when $target_type is a Yeti, a Walking Corpse, or even a custom Pig unit?
Main UMC campaigns: The Ravagers - now for 1.16, with new bugs!
Old UMC works: The Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
newfrenchy83
Code Contributor
Posts: 172
Joined: October 6th, 2017, 12:57 pm

Re: Wesnoth segfault with [transform_unit]

Post by newfrenchy83 »

i don't know, but it is strange what the game crash with a unit_type and no wither others.
User avatar
WhiteWolf
Forum Moderator
Posts: 769
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Wesnoth segfault with [transform_unit]

Post by WhiteWolf »

OK, it's clear that more focused information is needed.
I inserted this simple test code to a mainline campaign (Heir to the Throne's 1st scenario):

Code: Select all

[event]
	name=attacker hits
	first_time_only=no
	id=REMOVE_ME_LATER_test

	{VARIABLE target_type (Giant Rat)}
	[transform_unit]
		id=$second_unit.id
		transform_to="$target_type"
	[/transform_unit]
[/event]
No special units, just this plain event - and this actually makes Wesnoth crash to desktop. With this event, any* attack results in a segmentation fault, in the vanilla game, without any mods or hocus pocus.

*However, not always. It seems VERY random. For example: if I hit a debug-spawned Flare Drake with Delfador's ranged attack, it's a crash. If I hit a debug-spawned Drake Warden with Delfador's ranged attack - it works fine, gets transformed and no crash. :hmm: I'm still trying to make some sense of the pattern, but what could honestly be so different with these units, that ends in so different results.

Now I find this very, very strange. To me this sounds too strange, like a bug that's too serious to be the game's fault alone, so I booted up another computer, that has a newer Debian distribution (but still Wesnoth 1.14.5), but it's the same results!
Conclusion:
  • Inserting the above event to any vanilla campaign
  • And hitting a debug spawned Drake Flare for example with for example a Mage
  • seems a sure way to reproduce the issue reliably
I will also try to test it with the newest 1.14.12 build on Steam on a Windows computer, see if it's the same. But I hope this can help some one go on from here.

EDITED:
I'm still trying to make some sense of the pattern, but what could honestly be so different with these units, that ends in so different results.
In the meantime, here is the answer:
Using a ranged attack on a unit that also has a ranged attack, will result in crash. Anything else is fine: with melee you can attack anything, with ranged you can attack units that only have a melee attack, that will work fine. Ranged attack on a unit that can answer with a ranged attack will cause a definite crash.
Main UMC campaigns: The Ravagers - now for 1.16, with new bugs!
Old UMC works: The Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Wesnoth segfault with [transform_unit]

Post by gfgtdf »

I was able to repropduce this with the code given in the last comment in 1.15.3, furthermore the problem seems to vanish if i check uncheck "show combat" in the preferences so i suspect the drawing code.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: Wesnoth segfault with [transform_unit]

Post by gfgtdf »

I still havent fgured out how to debug an application this linux computer i'm currently on. But if someone could generatea stacktrace that'd be really helpful on this issue.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
Pentarctagon
Project Manager
Posts: 5564
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Wesnoth segfault with [transform_unit]

Post by Pentarctagon »

Backtrace:

Code: Select all

#0  0x0000555555d6f58e in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count(std::__weak_count<(__gnu_cxx::_Lock_policy)2> const&) (this=0x7fffffffafc8, __r=...) at /usr/include/c++/7/bits/shared_ptr_base.h:849
#1  0x0000555555e7bf29 in std::__shared_ptr<attack_type const, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<attack_type, void>(std::__weak_ptr<attack_type, (__gnu_cxx::_Lock_policy)2> const&) (this=0x7fffffffafc0, __r=...)
    at /usr/include/c++/7/bits/shared_ptr_base.h:1147
#2  0x0000555555e7aa4b in std::shared_ptr<attack_type const>::shared_ptr<attack_type, void>(std::weak_ptr<attack_type> const&) (this=0x7fffffffafc0, __r=<error reading variable: Cannot access memory at address 0x8>)
    at /usr/include/c++/7/bits/shared_ptr.h:266
#3  0x0000555555e79e05 in std::enable_shared_from_this<attack_type>::shared_from_this() const (this=0x0) at /usr/include/c++/7/bits/shared_ptr.h:644
#4  0x0000555555f1f008 in unit_display::unit_attack(display*, game_board&, map_location const&, map_location const&, int, attack_type const&, std::shared_ptr<attack_type const>, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const*) (disp=0x7fff783b8980, board=..., a=..., b=..., damage=0, attack=..., secondary_attack=
    std::shared_ptr<const attack_type> (use count 5, weak count 1) = {...}, swing=2, hit_text="", drain_amount=0, att_text="", extra_hit_sounds=0x7fffffffb320) at src/units/udisplay.cpp:640
#5  0x0000555555fd7afd in (anonymous namespace)::attack::perform_hit(bool, statistics::attack_context&) (this=0x7fffffffb740, attacker_turn=false, stats=...) at src/actions/attack.cpp:1074
#6  0x0000555555fda264 in (anonymous namespace)::attack::perform() (this=0x7fffffffb740) at src/actions/attack.cpp:1420
#7  0x0000555555fdaf53 in attack_unit(map_location const&, map_location const&, int, int, bool) (attacker=..., defender=..., attack_with=1, defend_with=1, update_display=true) at src/actions/attack.cpp:1542
#8  0x0000555555fdafe9 in attack_unit_and_advance(map_location const&, map_location const&, int, int, bool) (attacker=..., defender=..., attack_with=1, defend_with=1, update_display=true) at src/actions/attack.cpp:1551
#9  0x0000555555e24478 in synced_command_func_attack(config const&, bool, bool, synced_command::error_handler_function) (child=..., show=true, error_handler=...) at src/synced_commands.cpp:227
#10 0x0000555555e2b67e in synced_context::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, config const&, bool, bool, std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)>) (commandname="attack", data=..., use_undo=true, show=true, error_handler=...) at src/synced_context.cpp:71
#11 0x0000555555e2b8a0 in synced_context::run_and_store(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, config const&, bool, bool, std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)>) (commandname="attack", data=..., use_undo=true, show=true, error_handler=...) at src/synced_context.cpp:96
#12 0x0000555555e2b962 in synced_context::run_and_throw(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, config const&, bool, bool, std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)>) (commandname="attack", data=..., use_undo=true, show=true, error_handler=...) at src/synced_context.cpp:106
#13 0x000055555632e76d in events::mouse_handler::attack_enemy_(map_location const&, map_location const&, int) (this=0x7fffffffcfd8, att_loc=..., def_loc=..., choice=1) at src/mouse_events.cpp:1363
#14 0x000055555632e01d in events::mouse_handler::attack_enemy(map_location const&, map_location const&, int) (this=0x7fffffffcfd8, attacker_loc=..., defender_loc=..., choice=1) at src/mouse_events.cpp:1302
#15 0x000055555632b516 in events::mouse_handler::move_action(bool) (this=0x7fffffffcfd8, browse=false) at src/mouse_events.cpp:888
#16 0x000055555632af9d in events::mouse_handler::select_or_action(bool) (this=0x7fffffffcfd8, browse=false) at src/mouse_events.cpp:819
#17 0x000055555654ff16 in play_controller::hotkey_handler::select_and_action() (this=0x555557ceb180) at src/hotkey/hotkey_handler.cpp:122
#18 0x000055555680a3f8 in hotkey::command_executor::do_execute_command(hotkey::hotkey_command const&, int, bool, bool) (this=0x555557ceb180, cmd=..., press=true, release=false) at src/hotkey/command_executor.cpp:336
#19 0x0000555556550a22 in play_controller::hotkey_handler::do_execute_command(hotkey::hotkey_command const&, int, bool, bool) (this=0x555557ceb180, cmd=..., index=-1, press=true, release=false) at src/hotkey/hotkey_handler.cpp:271
#20 0x000055555680ba87 in hotkey::command_executor::execute_command_wrap(hotkey::command_executor::queued_command const&) (this=0x555557ceb180, command=...) at src/hotkey/command_executor.cpp:619
#21 0x000055555680c66f in hotkey::command_executor::run_queued_commands() (this=0x555557ceb180) at src/hotkey/command_executor.cpp:759
#22 0x000055555680b639 in hotkey::run_events(hotkey::command_executor*) (executor=0x555557ceb180) at src/hotkey/command_executor.cpp:574
#23 0x000055555680b574 in hotkey::mbutton_event(SDL_Event const&, hotkey::command_executor*) (event=..., executor=0x555557ceb180) at src/hotkey/command_executor.cpp:546
#24 0x0000555556126121 in controller_base::handle_event(SDL_Event const&) (this=0x7fffffffce90, event=...) at src/controller_base.cpp:185
#25 0x00005555567d8716 in events::pump() () at src/events.cpp:742
#26 0x0000555556126b7e in controller_base::play_slice(bool) (this=0x7fffffffce90, is_delay_enabled=true) at src/controller_base.cpp:353
#27 0x0000555556343e00 in play_controller::play_slice_catch() (this=0x7fffffffce90) at src/play_controller.cpp:1090
#28 0x0000555556351d86 in playsingle_controller::play_human_turn() (this=0x7fffffffce90) at src/playsingle_controller.cpp:478
#29 0x00005555563513ce in playsingle_controller::play_side_impl() (this=0x7fffffffce90) at src/playsingle_controller.cpp:396
#30 0x0000555556344574 in play_controller::play_side() (this=0x7fffffffce90) at src/play_controller.cpp:1181
#31 0x00005555563448dc in play_controller::play_turn() (this=0x7fffffffce90) at src/play_controller.cpp:1222
#32 0x000055555634fa25 in playsingle_controller::play_scenario_main_loop() (this=0x7fffffffce90) at src/playsingle_controller.cpp:174
#33 0x0000555556350330 in playsingle_controller::play_scenario(config const&) (this=0x7fffffffce90, level=...) at src/playsingle_controller.cpp:271
#34 0x00005555561ea939 in campaign_controller::playsingle_scenario(end_level_data&) (this=0x7fffffffd550, end_level=...) at src/game_initialization/playcampaign.cpp:197
#35 0x00005555561eae61 in campaign_controller::play_game() (this=0x7fffffffd550) at src/game_initialization/playcampaign.cpp:284
#36 0x0000555555afb53a in game_launcher::launch_game(game_launcher::RELOAD_GAME_DATA) (this=0x55555768c3c0, reload=game_launcher::RELOAD_DATA) at src/game_launcher.cpp:1025
#37 0x000055555597ea91 in do_gameloop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) (args=std::vector of length 1, capacity 1 = {...}) at src/wesnoth.cpp:939
#38 0x000055555597f2d9 in main(int, char**) (argc=1, argv=0x7fffffffe5f8) at src/wesnoth.cpp:1137
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
WhiteWolf
Forum Moderator
Posts: 769
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Wesnoth segfault with [transform_unit]

Post by WhiteWolf »

Should I open an issue on github for this?
Main UMC campaigns: The Ravagers - now for 1.16, with new bugs!
Old UMC works: The Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
User avatar
Pentarctagon
Project Manager
Posts: 5564
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Wesnoth segfault with [transform_unit]

Post by Pentarctagon »

That'd be good, yeah.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
WhiteWolf
Forum Moderator
Posts: 769
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Wesnoth segfault with [transform_unit]

Post by WhiteWolf »

Done :) #4927
Main UMC campaigns: The Ravagers - now for 1.16, with new bugs!
Old UMC works: The Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
Post Reply