D域推导把域引用搞成域中了.
// dmd -dip1000
@safe:
struct Correct {
private int* ptr;
int* get() return { return ptr; }
}
struct Faulty(T) {
private T* ptr;
T* get() return { return ptr; }
}
struct Workaround(T) {
private T* ptr;
T* get() return {
return *&ptr; // *&绕过
}
}
// 失败(应)
unittest {
int* outlive;
Correct c;
outlive = c.get(); // error
}
// 编译(不应该)
unittest {
int* outlive;
Faulty!int f;
outlive = f.get(); // 应为错
}
// 失败(应该)
unittest {
int* outlive;
Workaround!int w;
outlive = w.get(); // error
}
1ag0aep6g:
真的可这样返回有问题指针吗?事实上,测试用例只返回null.
似乎无属性推断,DMD假设get可能返回有问题的指针.但带属性推断,DMD查看实际返回表达式.
StanislavBlinov:
当然可以.ptr指向及值来源,与该测试用例无关,因此省略.
ag0aep6g:
请举例.尝试返回有问题指针时,DMD显示与"正确"情况下相同错误.
StanislavBlinov:
在构造器中分配它,析构器中释放它,禁用复制和赋值.
ag0aep6g:
我想到DIP1000时,容易想到栈指针.但是,是的也应该允许malloc/free.
完整示例:
import core.stdc.stdlib: free, malloc;
struct Faulty
{
private int* ptr;
this(int v) @trusted
{
ptr = cast(int*) malloc(int.sizeof);
*ptr = v;
}
~this() @trusted { if (ptr !is null) free(ptr); }
@disable this(this);
@disable void opAssign(Faulty);
int* get1() @safe return { return ptr; }
int* get2()() @safe return { return ptr; }
}
void main() @safe
{
int* outlive;
{
auto f1 = Faulty(42);
outlive = f1.get1(); /* 错误 */
outlive = f1.get2(); /* 应为错*/
}
/* `outlive`在此无效 */
}
推断该方法为"中域".奇怪的是,用pragma(msg,...)打印时没显示.
有了该信息,可构建即使无malloc/free和@trusted也能显示内存破坏的测试用例:
struct Faulty
{
private int x;
private int* unused;
int* get1() @safe return scope { return &x; }
}
int* f(int x) @safe
{
auto f = Faulty(x);
return f.get1(); /*返回栈指针*/
}
void main() @safe
{
int* p1 = f(42);
int* p2 = f(13);
import std.stdio;
writeln(*p1); /* 打印"13".错误. */
}
Dennis:
域推断转换返回引用为返回域,编译器内部混淆了return scope和return ref.
浙公网安备 33010602011771号