d懒参数问题
原文
当前懒参数表明创建引用局部变量的闭包.允许逃逸懒参数,而不在堆中分配局部变量,会导致泄漏某个栈域指针的内存错误.
extern(C) int printf(const char*,...) @safe;
auto foo(lazy double i) @safe
{
return { return i; } ;
}
auto bar() @safe
{
double i = 4.0;
return foo(i);
}
void baz() @safe
{
double[2] i = 3.14;
// 此值覆盖了4.0
// 用char[16] val = 'f'; 替代
// 可打印确定性垃圾
}
void main() @safe
{
auto x = bar();
baz();
printf("%f\n", x());
}
这打印了错误的3.14.潜在编译器可识别懒参数逃逸,并在堆上分配i=4.0,但因为是单独编译模型,不能通用解决,因此应该拒绝代码.
这是已知引用-引用错误的更复杂变体,包括返回出域的本地对象的引用:
ref int foo(ref int i) { return i; }
ref int bar() { int val; return foo(i); }
这是简化版本,它更好地解释了懒原理,并演示了类似的问题(也打印垃圾):
import std.stdio;
alias long[10] T;
T delegate() dg;
void foo(ref T i) @safe
{
dg = { return i; } ;
}
void bar() @safe
{
T i = 1;
foo(i);
}
void rewrite_stack() @safe
{
T tmp = -1;
}
void main()
{
bar();
rewrite_stack();
writeln(dg());
}
另一个测试用例:
//test.d
@safe:
auto toDg(E)(lazy E value)
{
return { return value; };
}
C t;
class C
{
auto getDg()
{
// return () => prop;
return toDg(prop);
}
final @property string prop()
{
assert(this is t);
return null;
}
}
void smashStack() {
int[1024] dummy = 0xcafebabe;
}
void main()
{
t = new C();
auto result = t.getDg();
smashStack();
result();
}
编译器要么拒绝代码(接受无效代码),要么生成闭包(错误码).
升级严重级,因为在@safe代码中,(根据是否覆盖栈)表现为潜在错误.
正是因为此类问题,我有个dip来弃用懒参数,用闭包代替它们,所以该特殊问题可能不会得到解决.
同时,我建议用闭包替换lazy参数.
降级懒到闭包,所以降级到正确的闭包类型并得到正确行为应该很容易,2022年有一个dconf在线讨论.
浙公网安备 33010602011771号