Bug 1512 – GC infinite loop when invalid user code runs.
Status
RESOLVED
Resolution
WONTFIX
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D1 (retired)
Platform
x86
OS
Windows
Creation time
2007-09-17T22:40:00Z
Last change time
2015-11-03T17:41:04Z
Assigned to
nobody
Creator
davidl
Comments
Comment #0 by davidl — 2007-09-17T22:40:01Z
class weirdclass
{
void func()
{
delete this;
}
}
void main()
{
auto inst=new weirdclass;
inst.func;
delete inst; // GC loops here
}
If I read disassembly correctly:
it loops in phobos code gcx.d
// Mark each free entry, so it doesn't get scanned
for (n = 0; n < B_PAGE; n++)
{
for (List *list = bucket[n]; list; list = list.next) // loops here
{
pool = findPool(list);
assert(pool);
pool.freebits.set(cast(uint)(cast(byte *)list - pool.baseAddr) / 16);
}
}
Though i didn't recompile phobos to confirm this.
Comment #1 by braddr — 2007-09-17T23:19:45Z
double delete == undefined behavior. Anything that happens after that point is fair game.
Comment #2 by shro8822 — 2007-09-17T23:59:35Z
yes, but a clean crash (or even a seg-v) would be much better
Comment #3 by braddr — 2007-09-18T00:38:29Z
Actually, the more interesting part of this that actually should be considered a bug... from the spec on part of what delete does:
The pointer, dynamic array, or reference is set to null after the delete is performed.
The question I have is: should inst have been set to null since it's the underlying storage for 'this'?
If it had been, then the second delete would have been a safe no-op.
Comment #4 by sean — 2007-09-18T13:35:56Z
[email protected] wrote:
> ------- Comment #3 from [email protected] 2007-09-18 00:38 -------
> Actually, the more interesting part of this that actually should be considered
> a bug... from the spec on part of what delete does:
>
> The pointer, dynamic array, or reference is set to null after the delete is
> performed.
>
> The question I have is: should inst have been set to null since it's the
> underlying storage for 'this'?
Within the context of weirdclass.func, 'this' is basically a local
variable, and it is likely set to null when 'delete this' is called.
However, I'm not sure it's reasonable to assert that all references to
the object should be set to null when the object is deleted. What if
weirdclass.func() were defined in a library and the code weren't
available for inspection when evaluating main()?
As for the endless loop, I'm not sure there's an efficient way to fix
the problem. When gc_free(p) is called, if p is non-null and points to
the head of a memory block owned by the GC, the block is added to the
free list. In this case, since the block is already on the free list it
ends up becoming a list of one element which points to itself.
To fix this, the GC would have to check for the presence of p on the
free list before adding it, which is an O(N) operation. If any change
were to be made, it should only occur in a debug build of the GC, and an
exception should be thrown if a double delete is detected. And for what
it's worth, I think the GC does offer features like this when built with
debug=LOGGING.
Comment #5 by davidl — 2007-09-19T02:10:06Z
it's related to the compiling command of phobos
when DFLAGS in src\phobos\win32.mak contains -O this bug is triggered.
with non optimized phobos, the following code on DMD 1.021 behaves correctly with printing : "exception caught"
class weirdclass
{
void func()
{
delete this;
}
}
void main()
{
auto inst=new weirdclass;
inst.func;
try
{
delete inst; // GC loops here
}
catch(Object o)
{
printf("exception caught");
}
}
Comment #6 by davidl — 2007-09-19T02:30:55Z
oops, it's not related to optimization.
it's the most weird bug in the world, it's related to -unittest.
once compiling your phobos with -unittest , the app goes all ok, and fine.
once compiling your phobos without -unittest, the app loops
Comment #7 by davidl — 2007-09-19T02:54:16Z
I don't know if the following is the sane check. But this prevent the GC from looping in this case.
add to phobos\internal\gc\gcx.d
line 1570:
if(list is list.next)
{
throw new Exception("looping while we try to free the list!");
}
Comment #8 by davidl — 2007-09-19T03:03:18Z
tango doesn't have such problem. So there must be better solution
Comment #9 by andrej.mitrovich — 2011-05-24T23:22:00Z
2.053:
object.Error: Access Violation
----------------
40D554
40D3CB
----------------
I guess that means fixed?
Comment #10 by safety0ff.bugz — 2013-10-31T02:25:49Z
Works for me, recent versions of DMD, LDC give: Error: Cannot modify 'this' inside func.
Comment #11 by safety0ff.bugz — 2013-10-31T02:34:55Z
(In reply to comment #10)
> Works for me, recent versions of DMD, LDC give: Error: Cannot modify 'this'
> inside func.
For D2, probably still valid for D1 (what it is marked as.)
Comment #12 by andrei — 2015-11-03T17:41:04Z
It's unlikely this D1 issue will get worked on, if anyone plans to work on it feel free to reopen.