zorael / kameloso

IRC bot with Twitch support
Boost Software License 1.0
9 stars 3 forks source link

Memory corruption when compiled with `dmd -release` #159

Closed zorael closed 1 year ago

zorael commented 1 year ago

The immediate workaround is unfortunately to just not use dmd for optimised builds. ldc and gdc are much better at optimising anyway, so they are in all aspects the better choice.

Occurs when you invoke Admin's get and set commands, as well as Help's help, when the program was compiled with dmd's optimisations. Common to all three is that they send delegates to the main thread which includes closures of the arguments passed to the functions they were nested in. When these delegates are called (in main.d:messageFiber), the program invariably segfaults. Attempts to modify the code merely makes it segfault earlier in the callstack.

Example from a call to get:

Thread 1 "kameloso" received signal SIGSEGV, Segmentation fault.
#0  0x0000555555e80a40 in core.internal.gc.impl.conservative.gc.ConservativeGC.runLocked!(core.internal.gc.impl.conservative.gc.ConservativeGC.mallocNoSync(ulong, uint, ref ulong, const(TypeInfo)), core.internal.gc.impl.conservative.gc.mallocTime, core.internal.gc.impl.conservative.gc.numMallocs, ulong, uint, ulong, const(TypeInfo)).runLocked(ref ulong, ref uint, ref ulong, ref const(TypeInfo)) ()
#1  0x0000555555e7859a in core.internal.gc.impl.conservative.gc.ConservativeGC.qalloc(ulong, uint, scope const(TypeInfo)) ()
#2  0x0000555555df251f in gc_qalloc ()
#3  0x0000555555df919c in _d_newitemiT ()
#4  0x0000555555b3b65c in ref std.variant.VariantN!(32uL).VariantN std.variant.VariantN!(32uL).VariantN.__ctor!(kameloso.messaging.Message).__ctor(kameloso.messaging.Message) (this=..., value=...) at 2.102/../../src/phobos/std/variant.d:726
#5  0x0000555555b3b558 in ref std.concurrency.Message std.concurrency.Message.__ctor!(kameloso.messaging.Message).__ctor(std.concurrency.MsgType, kameloso.messaging.Message) (this=..., _param_1=..., t=<incomplete type>) at 2.102/../../src/phobos/std/concurrency.d:171
#6  0x0000555555b3b4b0 in void std.concurrency._send!(kameloso.messaging.Message)._send(std.concurrency.MsgType, std.concurrency.Tid, kameloso.messaging.Message) (_param_2=..., tid=..., type=<incomplete type>) at 2.102/../../src/phobos/std/concurrency.d:719
#7  0x0000555555b3b3c4 in void kameloso.messaging.chan!(0).chan(kameloso.plugins.common.core.IRCPluginState, const(immutable(char)[]), const(immutable(char)[]), const(std.typecons.Flag!("quiet").Flag), const(std.typecons.Flag!("background").Flag), const(immutable(char)[])) (caller=43, __caller_8=93825002053285, background=false, quiet=false, content=18, __content_8=140737342526720, channelName=..., state=...) at 2.102/../../src/phobos/std/concurrency.d:709
#8  0x0000555555b4470e in void kameloso.messaging.privmsg!(0).privmsg(kameloso.plugins.common.core.IRCPluginState, const(immutable(char)[]), const(immutable(char)[]), const(immutable(char)[]), const(std.typecons.Flag!("quiet").Flag), const(std.typecons.Flag!("background").Flag), const(immutable(char)[])) (caller=18, __caller_8=18, background=18, quiet=18, content=18, __content_8=18, nickname=18, __nickname_8=18, channel=11, __channel_8=0x7ffff74ef443, state=...) at source/kameloso/messaging.d:369
#9  0x0000555555b52817 in void kameloso.plugins.admin.base.onCommandGet(kameloso.plugins.admin.base.AdminPlugin, const(dialect.defs.IRCEvent)).dg(immutable(char)[], immutable(char)[], immutable(char)[]) (__capture=0x7ffff74f2000, value=4, __value_8=140737342158864, setting=7, __setting_8=0x7ffff74ef46a, pluginName=5, __pluginName_8=0x7ffff74ef464) at source/kameloso/plugins/admin/base.d:916
#10 0x0000555555b2c0ae in void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso).peekGetSet(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]).apply() (__capture=0x7ffff7f88730) at source/kameloso/main.d:469
#11 0x0000555555b2bd62 in void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso).peekGetSet(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]) (__capture=0x7ffff74cbd40, contextual=13, __contextual_8=140737342534756, setSettingDg=140737342315520, __setSettingDg_8=0, getSettingDg=..., peekDg=0, __peekDg_8=0, _param_0=...) at source/kameloso/main.d:510
#12 0x0000555555b40fed in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).onStandardMsg(ref std.concurrency.Message) (__capture=0x7ffff7f88c30, msg=...) at 2.102/../../src/phobos/std/concurrency.d:2162
#13 0x0000555555b4149e in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).scan(ref std.concurrency.List!(std.concurrency.Message).List) (__capture=0x7ffff7f88e50, list=...) at 2.102/../../src/phobos/std/concurrency.d:2246
#14 0x0000555555b40b38 in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*) (this=..., _param_5=0x555555b2dc68 <scope @safe void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso).__lambda10(std.variant.VariantN!(32uL).VariantN)>, _param_4=..., _param_3=..., _param_2=..., _param_1=..., _param_0=...) at 2.102/../../src/phobos/std/concurrency.d:2323
#15 0x0000555555b2ad96 in void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso) (instance=...) at 2.102/../../src/phobos/std/concurrency.d:264
#16 0x0000555555b2ea68 in void kameloso.main.mainLoop(ref kameloso.kameloso.Kameloso).__lambda5() (__capture=0x7ffff7f85020) at source/kameloso/main.d:919
#17 0x0000555555df5035 in core.thread.context.Callable.opCall() ()
#18 0x0000555555e3b520 in fiber_entryPoint ()
#19 0x0000000000000000 in ?? ()

Example from a call to help:

Thread 1 "kameloso" received signal SIGSEGV, Segmentation fault.
#0  0x0000555555b3b827 in long std.variant.VariantN!(32uL).VariantN.handler!(kameloso.messaging.Message).handler(std.variant.VariantN!(32uL).VariantN.OpID, ubyte[32]*, void*) (parm=0x7ffff74f2400, pStore=0x7ffff7f85d30, selector=<incomplete type>) at 2.102/../../src/phobos/std/variant.d:261
#1  0x0000555555b3b6d6 in ref std.variant.VariantN!(32uL).VariantN std.variant.VariantN!(32uL).VariantN.__ctor!(kameloso.messaging.Message).__ctor(kameloso.messaging.Message) (this=..., value=...) at 2.102/../../src/phobos/std/variant.d:733
#2  0x0000555555b3b558 in ref std.concurrency.Message std.concurrency.Message.__ctor!(kameloso.messaging.Message).__ctor(std.concurrency.MsgType, kameloso.messaging.Message) (this=..., _param_1=..., t=<incomplete type>) at 2.102/../../src/phobos/std/concurrency.d:171
#3  0x0000555555b3b4b0 in void std.concurrency._send!(kameloso.messaging.Message)._send(std.concurrency.MsgType, std.concurrency.Tid, kameloso.messaging.Message) (_param_2=..., tid=..., type=<incomplete type>) at 2.102/../../src/phobos/std/concurrency.d:719
#4  0x0000555555b44835 in void kameloso.messaging.privmsg!(0).privmsg(kameloso.plugins.common.core.IRCPluginState, const(immutable(char)[]), const(immutable(char)[]), const(immutable(char)[]), const(std.typecons.Flag!("quiet").Flag), const(std.typecons.Flag!("background").Flag), const(immutable(char)[])) (caller=199, __caller_8=199, background=199, quiet=199, content=199, __content_8=199, nickname=199, __nickname_8=199, channel=0, __channel_8=0x0, state=...) at 2.102/../../src/phobos/std/concurrency.d:709
#5  0x0000555555be5097 in void kameloso.plugins.help.sendSpecificPluginListing(kameloso.plugins.help.HelpPlugin, ref const(dialect.defs.IRCEvent), kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]]) (allPluginCommands=[18] = {...}, event=..., plugin=0x7ffff74bb000) at source/kameloso/plugins/help.d:276
#6  0x0000555555be45a2 in void kameloso.plugins.help.onCommandHelp(kameloso.plugins.help.HelpPlugin, const(dialect.defs.IRCEvent)).dg(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]]) (__capture=0x7ffff74e4c00, allPluginCommands=[24] = {...}) at source/kameloso/plugins/help.d:106
#7  0x0000555555b2bc0c in void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso).peekGetSet(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]) (__capture=0x7ffff74cbd40, contextual=0, __contextual_8=0, setSettingDg=24, __setSettingDg_8=0, getSettingDg=..., peekDg=140737342491648, __peekDg_8=93824999113560, _param_0=...) at source/kameloso/main.d:438
#8  0x0000555555b40fed in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).onStandardMsg(ref std.concurrency.Message) (__capture=0x7ffff7f88c30, msg=...) at 2.102/../../src/phobos/std/concurrency.d:2162
#9  0x0000555555b4149e in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).scan(ref std.concurrency.List!(std.concurrency.Message).List) (__capture=0x7ffff7f88e50, list=...) at 2.102/../../src/phobos/std/concurrency.d:2246
#10 0x0000555555b40b38 in bool std.concurrency.MessageBox.get!(core.time.Duration, void delegate(kameloso.thread.ThreadMessage) scope, void delegate(kameloso.messaging.Message) scope, void delegate(kameloso.thread.OutputRequest) scope, void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), void function(std.variant.VariantN!(32uL).VariantN) scope @safe*).get(core.time.Duration, scope void delegate(kameloso.thread.ThreadMessage) scope, scope void delegate(kameloso.messaging.Message) scope, scope void delegate(kameloso.thread.OutputRequest) scope, scope void delegate(kameloso.thread.ThreadMessage.PeekGetSet, shared(void delegate(kameloso.plugins.common.core.IRCPlugin.CommandMetadata[immutable(char)[]][immutable(char)[]])), shared(void delegate(immutable(char)[], immutable(char)[], immutable(char)[])), shared(void delegate(bool)), immutable(char)[]), scope void function(std.variant.VariantN!(32uL).VariantN) scope @safe*) (this=..., _param_5=0x555555b2dc68 <scope @safe void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso).__lambda10(std.variant.VariantN!(32uL).VariantN)>, _param_4=..., _param_3=..., _param_2=..., _param_1=..., _param_0=...) at 2.102/../../src/phobos/std/concurrency.d:2323
#11 0x0000555555b2ad96 in void kameloso.main.messageFiber(ref kameloso.kameloso.Kameloso) (instance=...) at 2.102/../../src/phobos/std/concurrency.d:264
#12 0x0000555555b2ea68 in void kameloso.main.mainLoop(ref kameloso.kameloso.Kameloso).__lambda5() (__capture=0xc) at source/kameloso/main.d:919
#13 0x0000555555df5035 in core.thread.context.Callable.opCall() ()
#14 0x0000555555e3b520 in fiber_entryPoint ()
#15 0x0000000000000000 in ?? ()
zorael commented 1 year ago

The Onliners and Counter plugins are also affected, since they also peek plugin commands to ensure no oneliners or counters are created that collide with an existing command.

zorael commented 1 year ago

Worked around in 4cd3fe0c5be253a57c12bfb0183ec025f1e07ff3.

The new approach doesn't go through concurrency messages, which seemed to be common factor that made all other workarounds fail.