June 10, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

--- Comment #18 from Iain Buclaw <ibuclaw@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
```

--
June 10, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

--- Comment #19 from Iain Buclaw <ibuclaw@gdcproject.org> ---
Lessons inferred from this.

Don't use `Mem.xrealloc` on a `dmd.root.array.Array(T)` type!

--
June 10, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--- Comment #20 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #15302 "Fix 23978 - ICE: dip1021 memory corruption" was merged into stable:

- 32a4a5dc52cd6f6fc812ae76ac7d654518d4492d by Dennis Korpel:
  Fix 23978 - ICE: EscapeBy[] is malloced, but contains GC-allocated objects

https://github.com/dlang/dmd/pull/15302

--
June 11, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

Witold Baryluk <witold.baryluk+d@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |witold.baryluk+d@gmail.com

--
June 16, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

--- Comment #21 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #15325 "merge stable" was merged into master:

- 167b0504293926b3f9cecbb67b05e1e50f2150d5 by Dennis:
  Fix 23978 - ICE: EscapeBy[] is malloced, but contains GC-allocated objects
(#15302)

https://github.com/dlang/dmd/pull/15325

--
June 16, 2023
https://issues.dlang.org/show_bug.cgi?id=23978

--- Comment #22 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #15310 "Merge stable" was merged into master:

- 167b0504293926b3f9cecbb67b05e1e50f2150d5 by Dennis:
  Fix 23978 - ICE: EscapeBy[] is malloced, but contains GC-allocated objects
(#15302)

https://github.com/dlang/dmd/pull/15310

--
1 2 3
Next ›   Last »