Fix Issue 9975 - pointsTo asserts because of false pointer in union

This commit is contained in:
monarch dodra 2013-04-26 17:35:44 +03:00
parent 22c75c7904
commit e44adcd9ed

View file

@ -865,22 +865,34 @@ Returns $(D true) if $(D source)'s representation embeds a pointer
that points to $(D target)'s representation or somewhere inside that points to $(D target)'s representation or somewhere inside
it. it.
Note that evaluating $(D pointsTo(x, x)) checks whether $(D x) has If $(D source) is or contains a dynamic array, then, then pointsTo will check
if there is overlap between the dynamic array and $(D target)'s representation.
If $(D source) is or contains a union, then every member of the union is
checked for embedded pointers. This may lead to false positives, depending on
which should be considered the "active" member of the union.
If $(D source) is a class, then pointsTo will handle it as a pointer.
If $(D target) is a pointer, a dynamic array or a class, then pointsTo will only
check if $(D source) points to $(D target), $(B not) what $(D target) references.
Note: Evaluating $(D pointsTo(x, x)) checks whether $(D x) has
internal pointers. This should only be done as an assertive test, internal pointers. This should only be done as an assertive test,
as the language is free to assume objects don't have internal pointers as the language is free to assume objects don't have internal pointers
(TDPL 7.1.3.5). (TDPL 7.1.3.5).
*/ */
bool pointsTo(S, T, Tdummy=void)(auto ref const S source, auto ref const T target) @trusted pure nothrow bool pointsTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
if ((__traits(isRef, source) || isDynamicArray!S) && // lvalue or slice rvalue if (__traits(isRef, source) || isDynamicArray!S ||
(__traits(isRef, target) || isDynamicArray!T)) // lvalue or slice rvalue isPointer!S || is(S == class))
{ {
static if (is(S P : U*, U)) static if (isPointer!S || is(S == class))
{ {
const m = cast(void*) source, const m = cast(void*) source,
b = cast(void*) &target, e = b + target.sizeof; b = cast(void*) &target, e = b + target.sizeof;
return b <= m && m < e; return b <= m && m < e;
} }
else static if (is(S == struct)) else static if (is(S == struct) || is(S == union))
{ {
foreach (i, Subobj; typeof(source.tupleof)) foreach (i, Subobj; typeof(source.tupleof))
if (pointsTo(source.tupleof[i], target)) return true; if (pointsTo(source.tupleof[i], target)) return true;
@ -902,10 +914,11 @@ bool pointsTo(S, T, Tdummy=void)(auto ref const S source, auto ref const T targe
} }
} }
// for shared objects // for shared objects
bool pointsTo(S, T)(ref const shared S source, ref const shared T target) @trusted pure nothrow bool pointsTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
{ {
return pointsTo!(shared S, shared T, void)(source, target); return pointsTo!(shared S, shared T, void)(source, target);
} }
unittest unittest
{ {
struct S1 { int a; S1 * b; } struct S1 { int a; S1 * b; }
@ -947,7 +960,6 @@ unittest
//dynamic arrays don't point to each other, or slices of themselves //dynamic arrays don't point to each other, or slices of themselves
assert(!pointsTo(darr, darr)); assert(!pointsTo(darr, darr));
assert(!pointsTo(darr, darr[0 .. 1]));
assert(!pointsTo(darr[0 .. 1], darr)); assert(!pointsTo(darr[0 .. 1], darr));
//But they do point their elements //But they do point their elements
@ -1005,6 +1017,75 @@ unittest
assert(!pointsTo(ss, ss)); //The array doesn't point itself. assert(!pointsTo(ss, ss)); //The array doesn't point itself.
} }
unittest //Unions
{
int i;
union U //Named union
{
size_t asInt = 0;
int* asPointer;
}
struct S
{
union //Anonymous union
{
size_t asInt = 0;
int* asPointer;
}
}
U u;
S s;
assert(!pointsTo(u, i));
assert(!pointsTo(s, i));
u.asPointer = &i;
s.asPointer = &i;
assert( pointsTo(u, i));
assert( pointsTo(s, i));
u.asInt = cast(size_t)&i;
s.asInt = cast(size_t)&i;
assert( pointsTo(u, i)); //logical false positive
assert( pointsTo(s, i)); //logical false positive
}
unittest //Classes
{
int i;
static class A
{
int* p;
}
A a = new A, b = a;
assert(!pointsTo(a, b)); //a does not point to b
a.p = &i;
assert(!pointsTo(a, i)); //a does not point to i
import std.typecons;
auto scoped = scoped!A();
a = scoped;
assert( pointsTo(a, scoped)); //a points to a class payload which is located inside scoped
}
unittest //alias this test
{
static int i;
static int j;
struct S
{
int* p;
@property int* foo(){return &i;}
alias foo this;
}
assert(is(S : int*));
S s = S(&j);
assert(!pointsTo(s, i));
assert( pointsTo(s, j));
assert( pointsTo(cast(int*)s, i));
assert(!pointsTo(cast(int*)s, j));
}
/********************* /*********************
* Thrown if errors that set $(D errno) occur. * Thrown if errors that set $(D errno) occur.
*/ */