[Issue 23978] [REG 2.103.0] ICE: dip1021 memory corruption
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Sat Jun 10 16:41:02 UTC 2023
https://issues.dlang.org/show_bug.cgi?id=23978
--- Comment #18 from Iain Buclaw <ibuclaw at gdcproject.org> ---
Back to valgrind/vgdb, set breakpoint in Mem::xrealloc if (p == 0x5eba660)
```
Thread 1 hit Breakpoint 2, Mem::xrealloc(void*, unsigned long) (p=0x5eba660,
size=832)
at src/dmd/root/rmem.d:92
92 if (isGCEnabled)
(gdb) monitor who_points_at 0x5eba698
==61853== Searching for pointers to 0x5eba698
==61853== *0x5eba690 points at 0x5eba698
Address 0x5eba690 is in a rw- anonymous segment
```
^--- We have 1 reference to the address that later causes issues.
```
(gdb) monitor who_points_at 0x5eba690
==61853== Searching for pointers to 0x5eba690
```
^--- But we still don't know where that reference is coming from.
```
(gdb) p *(void**)0x5eba698
$10 = (void *) 0x5e8aa00
(gdb) p **(void***)0x5eba698
$11 = (void *) 0x8f5a80 <vtable for dmd.declaration.VarDeclaration>
```
^--- It is initialized with a non-null value, that appears to be a
VarDeclaration class object.
```
(gdb) up
#1 0x0000000000549df5 in
_D3dmd6escape21checkMutableArgumentsFPSQBl6dscope5ScopeCQCc4func15FuncDeclarationCQDc5mtype12TypeFunctionCQEa10expression10ExpressionPSQFd4root5array__T5ArrayTQCcZQlbZb
(gag=false, arguments=0x4fb97e0, ethis=0x0,
tf=0x584de00, fd=0x4fbf990, sc=0x5883a10) at src/dmd/escape.d:103
103 auto newPtr = cast(EscapeBy*)mem.xrealloc(escapeBy.ptr, len *
EscapeBy.sizeof);
(gdb) p escapeBy
$12 = {{er = {byref = {length = 0, data = 0x0, smallarray = {0x0}}, byvalue = {
length = 0, data = {0x5e8aa00}, smallarray = {0x5e8aa00}}, byfunc = {
length = 0, data = 0x0, smallarray = {0x0}}, byexp = {length = 0,
data = 0x0, smallarray = {0x0}}, refRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}, expRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}}, param = 0x5e8fd80,
isMutable = false}, {er = {byref = {length = 0, data = 0x0, smallarray =
{
0x0}}, byvalue = {length = 0, data = {0x5e8ab00}, smallarray = {
0x5e8ab00}}, byfunc = {length = 0, data = 0x0, smallarray = {0x0}},
byexp = {length = 0, data = 0x0, smallarray = {0x0}},
refRetRefTransition = {length = 0, data = 0x0, smallarray = {false}},
expRetRefTransition = {length = 0, data = 0x0, smallarray = {false}}},
param = 0x5e8fdb0, isMutable = false}, {er = {byref = {length = 0,
data = 0x0, smallarray = {0x0}}, byvalue = {length = 0, data = 0x0,
smallarray = {0x0}}, byfunc = {length = 0, data = 0x0, smallarray = {
0x0}}, byexp = {length = 0, data = 0x0, smallarray = {0x0}},
refRetRefTransition = {length = 0, data = 0x0, smallarray = {false}},
expRetRefTransition = {length = 0, data = 0x0, smallarray = {false}}},
param = 0x5e8fde0, isMutable = false}}
```
^--- Ah-ha! there's an address we've seen before.
```
(gdb) p escapeBy.ptr[0]
$13 = {er = {byref = {length = 0, data = 0x0, smallarray = {0x0}}, byvalue = {
length = 0, data = {0x5e8aa00}, smallarray = {0x5e8aa00}}, byfunc = {
length = 0, data = 0x0, smallarray = {0x0}}, byexp = {length = 0,
data = 0x0, smallarray = {0x0}}, refRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}, expRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}}, param = 0x5e8fd80, isMutable = false}
(gdb) p escapeBy.ptr[0].er.byvalue
$14 = {length = 0, data = {0x5e8aa00}, smallarray = {0x5e8aa00}}
(gdb) p escapeBy.ptr[0].er.byvalue.data.ptr
$15 = (dmd.declaration.VarDeclaration **) 0x5eba698
(gdb) p &escapeBy.ptr[0].er.byvalue.data.ptr
$16 = (dmd.declaration.VarDeclaration ***) 0x5eba690
```
^--- And there it is. 0x5eba690 is an address that's being pointed to by the
escapeByStorage global variable.
So the memory range from the base `.ptr` (0x5eba660) has a `data.ptr` self
reference to a part of itself (0x5eba698) thanks to the smallarray optimization
in Array(T).
We can all guess what's going to happen when we realloc this memory, but let's
finish stepping through runtime anyway for completeness sake.
```
Thread 1 hit Breakpoint 3,
_D3dmd6escape21checkMutableArgumentsFPSQBl6dscope5ScopeCQCc4func15FuncDeclarationCQDc5mtype12TypeFunctionCQEa10expression10ExpressionPSQFd4root5array__T5ArrayTQCcZQlbZb
(gag=false, arguments=0x4fb97e0, ethis=0x0,
tf=0x584de00, fd=0x4fbf990, sc=0x5883a10) at src/dmd/escape.d:105
105 memset(newPtr + escapeBy.length, 0, (len - escapeBy.length) *
EscapeBy.sizeof);
(gdb) p newPtr
$25 = (dmd.escape.checkMutableArguments.EscapeBy *) 0x5eef400
(gdb) p *newPtr
$26 = {er = {byref = {length = 0, data = 0x0, smallarray = {0x0}}, byvalue = {
length = 0, data = {0x5e8aa00}, smallarray = {0x5e8aa00}}, byfunc = {
length = 0, data = 0x0, smallarray = {0x0}}, byexp = {length = 0,
data = 0x0, smallarray = {0x0}}, refRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}, expRetRefTransition = {length = 0,
data = 0x0, smallarray = {false}}}, param = 0x5e8fd80, isMutable = false}
(gdb) p newPtr.er.byvalue.data.ptr
$27 = (dmd.declaration.VarDeclaration **) 0x5eba698
```
^--- No surprises there, the "newPtr" returned by the GC has a reference to the
old escapeBy.ptr memory (which the GC has just marked as free too).
```
(gdb) p &newPtr.er.byvalue.data.ptr
$28 = (dmd.declaration.VarDeclaration ***) 0x5eef430
```
^--- Confirmed! There's the pointer reference from the first valgrind run we
were looking for (0x5eef430).
```
Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x00000000006a33b5 in
_D3dmd4root3aav15dmd_aaGetRvalueFNaNbNiPSQBnQBmQBk2AAPvZQd
(key=0x4fbca00, aa=0x5ef7660) at src/dmd/root/aav.d:127
127 if (key == e.key)
(gdb) p aa.b
$34 = (dmd.root.aav.aaA **) 0x5eba660
(gdb) p &aa.b[7]
$35 = (dmd.root.aav.aaA **) 0x5eba698
(gdb) monitor who_points_at 0x5eba698
==61853== Searching for pointers to 0x5eba698
==61853== *0x5eef430 points at 0x5eba698
Address 0x5eef430 is in a rw- anonymous segment <-- !!! Here
==61853== *0xd964580 points at 0x5eba698
Address 0xd964580 is in a rw- anonymous segment
```
--
More information about the Digitalmars-d-bugs
mailing list