Bug 14699 – [REG2.062] ICE: segfaults on array with zero size
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-06-14T12:20:00Z
Last change time
2017-07-22T12:35:30Z
Keywords
ice, pull
Assigned to
nobody
Creator
tomer
Comments
Comment #0 by tomer — 2015-06-14T12:20:08Z
The code crashes both dmd2.66 and 2.67
struct Table(K, V, ushort capacity_) {
V[capacity_] values;
}
struct Set(K, ushort capacity_) {
Table!(K, ubyte[0], capacity_) tbl;
}
// this works
Table!(uint, ubyte[0], 10) thisWorks;
// this crashes
Set!(uint, 10) thisCrashesDmd;
void main() {}
The segfault:
Program received signal SIGSEGV, Segmentation fault.
0x00000000005639c0 in dtcat(dt_t**, dt_t*) ()
(gdb) bt
#0 0x00000000005639c0 in dtcat(dt_t**, dt_t*) ()
#1 0x0000000000550157 in Expression_toDt(Expression*, dt_t**)::ExpToDt::visit(ArrayLiteralExp*) ()
#2 0x00000000005500d8 in Expression_toDt(Expression*, dt_t**)::ExpToDt::visit(ArrayLiteralExp*) ()
#3 0x0000000000550910 in toDtElem(TypeSArray*, dt_t**, Expression*) ()
#4 0x0000000000550d6c in Expression_toDt(Expression*, dt_t**)::ExpToDt::visit(StructLiteralExp*) ()
#5 0x0000000000550c73 in Expression_toDt(Expression*, dt_t**)::ExpToDt::visit(StructLiteralExp*) ()
#6 0x00000000005506a7 in StructDeclaration_toDt(StructDeclaration*, dt_t**) ()
#7 0x000000000055086d in Type_toDt(Type*, dt_t**) ()
#8 0x0000000000543595 in toObjFile(Dsymbol*, bool)::ToObjFile::visit(VarDeclaration*) ()
#9 0x000000000054504d in toObjFile(Dsymbol*, bool) ()
#10 0x000000000052c974 in genObjFile(Module*, bool) ()
#11 0x0000000000405bf2 in tryMain(unsigned long, char const**) ()
Comment #1 by ketmar — 2015-06-14T16:04:16Z
it asserts on GNU/Linux: "Internal error: backend/dt.c 120".
and it asserts even with only "this works" line (i.e. having "this crashes" commented).
the following code triggers the bug on GNU/Linux, x86:
struct Table(K, V, ushort capacity_) {
V[capacity_] values;
}
Table!(uint, ubyte[0], 10) thisWorks;
dmd -c z00.d —> ICE.
it does so on git HEAD too.
this is triggered by `ubyte[0]`, changing it to `ubyte[1]` avoids the bug.
so i'm changing hardware info and subject.
p.s. it seems that there is unguarded `-1` somewhere in the compiler code, so `0‒1` results in `-1`, which triggers assertion in dt.c:120.
Comment #2 by ketmar — 2015-06-14T16:05:22Z
p.s. actually, it's enough to have a single line to trigger the bug:
ubyte[0][1] test;
that's it.
Comment #3 by ketmar — 2015-06-14T16:09:55Z
and here is the patch:
diff --git a/src/mtype.c b/src/mtype.c
index e15206d..4cbff57 100644
--- a/src/mtype.c
+++ b/src/mtype.c
@@ -4076,6 +4076,11 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
error(loc, "index %llu overflow for static array", (unsigned long long)d1);
goto Lerror;
}
+ else if (mulu(tbn->size(loc), d2, overflow) == 0)
+ {
+ error(loc, "index %llu underflow for static array", (unsigned long long)d1);
+ goto Lerror;
+ }
}
}
switch (tbn->ty)
Comment #4 by ketmar — 2015-06-14T16:11:20Z
sorry, slightly better patch:
diff --git a/src/mtype.c b/src/mtype.c
index e15206d..a464b49 100644
--- a/src/mtype.c
+++ b/src/mtype.c
@@ -4076,6 +4076,11 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc)
error(loc, "index %llu overflow for static array", (unsigned long long)d1);
goto Lerror;
}
+ else if (d2 == 0)
+ {
+ error(loc, "index %llu underflow for static array", (unsigned long long)d1);
+ goto Lerror;
+ }
}
}
switch (tbn->ty)
Comment #5 by ketmar — 2015-06-14T16:26:45Z
or a patch for those who prefers `ubyte[0]` to be valid (phobos using such thing, hehe):
diff --git a/src/todt.c b/src/todt.c
index 8ae752f..101d0bb 100644
--- a/src/todt.c
+++ b/src/todt.c
@@ -810,7 +810,7 @@ dt_t **toDtElem(TypeSArray *tsa, dt_t **pdt, Expression *e)
len /= ((StringExp *)e)->len;
if (e->op == TOKarrayliteral)
len /= ((ArrayLiteralExp *)e)->elements->dim;
- pdt = dtrepeat(pdt, *pdt, len - 1);
+ pdt = dtrepeat(pdt, *pdt, (len ? len - 1 : 0));
}
return pdt;
}
Comment #6 by k.hara.pg — 2015-06-15T10:45:49Z
(In reply to Ketmar Dark from comment #5)
> or a patch for those who prefers `ubyte[0]` to be valid (phobos using such
> thing, hehe):
[snip]
When tsa->size() == 0, toDtElem can return a dummy zero as the dt.
diff --git a/src/todt.c b/src/todt.c
index cd45664..6d5a476 100644
--- a/src/todt.c
+++ b/src/todt.c
@@ -773,10 +773,15 @@ dt_t **Type_toDt(Type *t, dt_t **pdt)
dt_t **toDtElem(TypeSArray *tsa, dt_t **pdt, Expression *e)
{
- //printf("TypeSArray::toDtElem()\n");
- size_t len = tsa->dim->toInteger();
- if (len)
+ //printf("TypeSArray::toDtElem() tsa = %s\n", tsa->toChars());
+ if (tsa->size(Loc()) == 0)
{
+ pdt = dtnzeros(pdt, 0);
+ }
+ else
+ {
+ size_t len = tsa->dim->toInteger();
+ assert(len);
pdt = dtend(pdt);
Type *tnext = tsa->next;
Type *tbn = tnext->toBasetype();
Comment #7 by ketmar — 2015-06-15T11:08:06Z
thanks. i don't know anything about glue code and backend, so i did it the least intrusive way i can. your fix is definitely better.