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
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,
as the language is free to assume objects don't have internal pointers
(TDPL 7.1.3.5).
*/
bool pointsTo(S, T, Tdummy=void)(auto ref const S source, auto ref const T target) @trusted pure nothrow
if ((__traits(isRef, source) || isDynamicArray!S) && // lvalue or slice rvalue
(__traits(isRef, target) || isDynamicArray!T)) // lvalue or slice rvalue
bool pointsTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
if (__traits(isRef, source) || isDynamicArray!S ||
isPointer!S || is(S == class))
{
static if (is(S P : U*, U))
static if (isPointer!S || is(S == class))
{
const m = cast(void*) source,
b = cast(void*) &target, e = b + target.sizeof;
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))
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
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);
}
unittest
{
struct S1 { int a; S1 * b; }
@ -947,7 +960,6 @@ unittest
//dynamic arrays don't point to each other, or slices of themselves
assert(!pointsTo(darr, darr));
assert(!pointsTo(darr, darr[0 .. 1]));
assert(!pointsTo(darr[0 .. 1], darr));
//But they do point their elements
@ -1005,6 +1017,75 @@ unittest
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.
*/