dip1000无中逃逸
import std.stdio;
@safe:
struct ScopeBuffer(T, size_t Len)
{
this(T[Len] buf, size_t len = 0)
{
this.buf = buf;
this.len = len;
}
// 用`return`正确发出编译错误,无,则编译器错误.
inout(T)[] opSlice(size_t lower, size_t upper) inout /*return*/
in
{
assert(lower <= len, "");
assert(upper <= len, "");
assert(lower <= upper,"");
}
do
{
return buf[lower .. upper];
//漏洞,如果opSlice无`中`,应在此发出`编译`错误.
}
T[Len] buf;
size_t len;
}
char[] fun()
{
char[4] buf = "abcd";
auto sb = ScopeBuffer!(char, 4)(buf, 4);
return sb[0..2];
//漏洞,除非有`中`,编译器允许`ScopeBuffer`中内部数据逃逸.
}
void main()
{
auto s = fun();
writeln(s);
}
用dmd -preview=dip1000 source.d编译.
期望,ScopeBuffer中缓冲的切片逃逸时,应发出编译错误.有中时正确发出错误,无中时应该却没有发出错误.
有趣的是,删除inout发出错误了.
删除模板,则行为正确了.
更简洁的示例:
import std.stdio;
@safe:
struct ScopeBuffer
{
this(char[4] init)
{
this.buf = init;
}
// 漏洞是`inout`在`this`上推导`return`.
inout(char)[] opSlice(size_t lower, size_t upper) inout
do
{
return buf[lower .. upper];
//漏洞,应该发出错误.
}
char[4] buf;
}
char[] fun()
{
char[4] buf = "abcd";
auto sb = ScopeBuffer(buf);
return sb[0..2];
}
void main()
{
auto s = fun();
writeln(s);
}
还未确定问题,但不在inout.简单示例:
@safe:
struct S {
this(int) { }
char[] opSlice() return { return buf[]; }
char[4] buf;
}
S bar();
char[] fun() {
return S()[];//S('\xff')返回的栈值引用逃逸了
return S(1)[]; // 错误,应相同
return bar()[]; //bar返回的栈值引用逃逸了
}
问题是应相同对待构造器调用与构字面/函数返回的临时值.1个问题,1个修复.
问题仍存在,下面为最小示例.
@safe:
struct ScopeBuffer
{
this(char[4] init)
{
this.buf = init;
}
inout(char)[] opSlice(size_t lower, size_t upper) inout
{
return buf[lower .. upper];
}
char[4] buf;
}
//...其余与上同.
它应产生栈分配内存指针逃逸了的错误.
更简化版示例:
@safe:
struct S {
//inout(char)* slice() inout return
//上面给出正确的错误
inout(char)* slice() inout/*无错误*/
{
return &buf;
}
char buf;
}
char* fun() {
S sb;
return sb.slice();
}
如果,切片为静态函数,并按引用传递sb作为第1参.编译器发出正确错误,因而,与本是个特例有关.
浙公网安备 33010602011771号