mirror of
https://github.com/dlang/phobos.git
synced 2025-05-03 08:30:33 +03:00
Fix Issue 9975 - pointsTo asserts because of false pointer in union
This commit is contained in:
parent
22c75c7904
commit
e44adcd9ed
1 changed files with 89 additions and 8 deletions
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue