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参.编译器发出正确错误,因而,与是个特例有关.

posted @   zjh6  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示