Bug 22616 – Infinity loop instead of InvalidMemoryOperationError during GC routine
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-12-21T12:01:33Z
Last change time
2022-12-26T03:24:12Z
Keywords
pull
Assigned to
No Owner
Creator
feklushkin.denis
Comments
Comment #0 by feklushkin.denis — 2021-12-21T12:01:33Z
Issue was introduced in v2.097.0
/+ dub.json:
{
"name": "test"
}
+/
class C
{
int i;
~this ()
{
// It is wrong to allocate during GC collection,
// but this failed assert allocates and must throw
// InvalidMemoryOperationError.
assert(i == 123);
}
}
void main()
{
auto c = new C;
}
```
DMD64 D Compiler v2.096.1 - OK
$ dub -f --compiler=dmd --single test.d
Performing "debug" build using dmd for x86_64.
test ~master: building configuration "application"...
Linking...
Running test
core.exception.InvalidMemoryOperationError@src/core/exception.d(647): Invalid memory operation
----------------
Program exited with code 1
(as expected)
DMD64 D Compiler v2.097.0 - Infinity wait
$ dub -f --compiler=dmd --single test.d
Performing "debug" build using dmd for x86_64.
test ~master: building configuration "application"...
Linking...
Running test
(stalled)
Stack after ctrl+c:
#0 0x00007ffff7d05176 in __GI___wait4 (pid=289204, stat_loc=0x7fffffffc68c, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:30
#1 0x00005555557babb3 in std.process.Pid.performWait(bool) ()
#2 0x0000555555700686 in dub.generators.build.BuildGenerator.runTarget(dub.internal.vibecompat.inet.path.NativePath, in dub.compilers.buildsettings.BuildSettings, immutable(char)[][], dub.generators.generator.GeneratorSettings) ()
#3 0x000055555570031b in dub.generators.build.BuildGenerator.performPostGenerateActions(dub.generators.generator.GeneratorSettings, in dub.generators.generator.ProjectGenerator.TargetInfo[immutable(char)[]]) ()
#4 0x00005555556e8806 in dub.generators.generator.ProjectGenerator.generate(dub.generators.generator.GeneratorSettings) ()
#5 0x000055555577e429 in dub.commandline.GenerateCommand.execute(dub.dub.Dub, immutable(char)[][], immutable(char)[][]) ()
#6 0x000055555577f4ee in dub.commandline.RunCommand.execute(dub.dub.Dub, immutable(char)[][], immutable(char)[][]) ()
#7 0x000055555571964f in dub.commandline.runDubCommandLine(immutable(char)[][]) ()
#8 0x00005555557e7258 in rt.dmain2._d_run_main2(char[][], ulong, extern(C) int(char[][]) function).runAll() ()
#9 0x00005555557e7155 in _d_run_main2 ()
#10 0x00005555557e6fae in _d_run_main ()
#11 0x00007ffff7c627ed in __libc_start_main (main=0x555555788050 <main>, argc=5, argv=0x7fffffffe7d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe7c8) at ../csu/libc-start.c:332
#12 0x000055555559b2da in _start ()
Comment #1 by feklushkin.denis — 2021-12-21T12:12:41Z
Wrong stack trace attached, correct is:
#0 __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=0x7fffffffdad0, rem=0x7fffffffdae0) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:67
#1 0x00007ffff7d053f3 in __GI___nanosleep (req=<optimized out>, rem=<optimized out>) at ../sysdeps/unix/sysv/linux/nanosleep.c:25
#2 0x00005555555ba090 in core.thread.osthread.Thread.sleep(core.time.Duration) ()
#3 0x00005555555bd6c9 in core.internal.spinlock.SpinLock.yield(ulong) shared ()
#4 0x00005555555bd67a in core.internal.spinlock.SpinLock.lock() shared ()
#5 0x00005555555c6dcb 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)) ()
#6 0x00005555555be702 in core.internal.gc.impl.conservative.gc.ConservativeGC.malloc(ulong, uint, const(TypeInfo)) ()
#7 0x000055555559d3db in gc_malloc ()
#8 0x0000555555599875 in _d_newclass ()
#9 0x00005555555a3029 in core.runtime.defaultTraceHandler(void*) ()
#10 0x000055555559db52 in _d_traceContext ()
#11 0x000055555559d942 in _d_createTrace ()
#12 0x0000555555598cbe in _d_throwdwarf ()
#13 0x00005555555c327c in core.internal.gc.impl.conservative.gc.Gcx.fullcollect(bool) ()
#14 0x00005555555c78d4 in core.internal.gc.impl.conservative.gc.ConservativeGC.runLocked!(core.internal.gc.impl.conservative.gc.ConservativeGC.fullCollectNoStack().go(core.internal.gc.impl.conservative.gc.Gcx*), core.internal.gc.impl.conservative.gc.Gcx*).runLocked(ref core.internal.gc.impl.conservative.gc.Gcx*) ()
#15 0x00005555555bfc54 in core.internal.gc.impl.conservative.gc.ConservativeGC.fullCollectNoStack() ()
#16 0x00005555555bfbea in core.internal.gc.impl.conservative.gc.ConservativeGC.collectNoStack() ()
#17 0x00005555555aac3f in gc_term ()
#18 0x000055555559da7b in rt_term ()
#19 0x0000555555598acb in rt.dmain2._d_run_main2(char[][], ulong, extern(C) int(char[][]) function).runAll() ()
#20 0x00005555555989ad in rt.dmain2._d_run_main2(char[][], ulong, extern(C) int(char[][]) function).tryExec(scope void() delegate) ()
#21 0x000055555559890e in _d_run_main2 ()
#22 0x000055555559866a in _d_run_main ()
#23 0x0000555555597712 in main (argc=1, argv=0x7fffffffe228) at /usr/include/dmd/druntime/import/core/internal/entrypoint.d:29
#24 0x00007ffff7c627ed in __libc_start_main (main=0x5555555976f0 <main>, argc=1, argv=0x7fffffffe228, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe218) at ../csu/libc-start.c:332
#25 0x00005555555975ea in _start ()
Comment #2 by moonlightsentinel — 2021-12-21T15:05:22Z
Comment #3 by pro.mathias.lang — 2021-12-21T16:37:25Z
The key is:
```
#7 0x000055555559d3db in gc_malloc ()
#8 0x0000555555599875 in _d_newclass ()
#9 0x00005555555a3029 in core.runtime.defaultTraceHandler(void*) ()
#10 0x000055555559db52 in _d_traceContext ()
#11 0x000055555559d942 in _d_createTrace ()
#12 0x0000555555598cbe in _d_throwdwarf ()
```
So it means we hit https://github.com/dlang/druntime/blob/fd9a45448244fb9dd4326520ad8526c540895eb0/src/core/runtime.d#L695
But that shouldn't be possible, since this function is guarded by a `GC.inFinalizer` check that would lead to it returning...
Comment #4 by moonlightsentinel — 2021-12-21T17:04:29Z
*** Issue 23555 has been marked as a duplicate of this issue. ***
Comment #6 by dlang-bot — 2022-12-18T01:20:33Z
@schveiguy updated dlang/dmd pull request #14710 "Remove GC for allocating traceinfo" fixing this issue:
- Remove GC for allocating traceinfo. Allow traces for
InvalidMemoryOperationError and other sensitive errors.
Fixes 20650,16641,22616.
https://github.com/dlang/dmd/pull/14710
Comment #7 by dlang-bot — 2022-12-26T03:24:12Z
dlang/dmd pull request #14710 "Avoid GC for allocating traceinfo" was merged into master:
- 374f20760e6c6183861dc599e1fb6379830a032a by Steven Schveighoffer:
Avoid GC for allocating traceinfo. Allow traces for
InvalidMemoryOperationError and other sensitive errors.
Fixes 20650,16641,22616.
https://github.com/dlang/dmd/pull/14710