d静态数组生存期

原文

如下代码非期望:

int[] foo()
{
    int[1024] static_array;
    // return static_array[];
    //返回`'static_array[]'`时逃逸了局部变量`'static_array'`的引用
    return null;
}

class A
{
    this(int[] inData)
    {
        data = inData;
    }

    int[] data;
}

void main()
{
    int[] arr;
    A a;
    {
        int[1024] static_array;
        arr = aSlice; // OK
        a = new A(aSlice); // OK
        arr = foo();
        //arr = foo();

    }
}

通过赋值aSlicearra,它似乎逃逸了域,我以为有错误,但代码编译得很好.
真的安全吗?
切片是原数组拥有的现有内存视图.切片不会分配内存.GC跟踪动态数组,分配的内存的所有引用,因此只要切片活跃,则原内存也活跃.

上分配静态数组,它们离开函数域时就失效了.同样,引用栈内存切片或其他指针也是如此.

这里重要的不是,而是.内部域中分配的内存使用函数栈,因此在退出函数前,所有内存都是有效的.
不,它不安全.可在程序头加@安全:行,(在重命名static_arrayaSlice后),它无法编译:
test.d(27):错误:赋值'aSlice'变量的地址给具有较长生命期的'arr'.
默认,假定所有内容都为@system.
退出域时,会调用析构器,等等.
谢谢,@safe对第一片代码管用,但是下面代码仍然可编译:

class A
{
    @safe
    this(int[] inData)
    {
        data = inData;
    }

    int[] data;
}

@safe
int[] foo()
{
    int[1024] static_array;
    //返回`'static_array[]'`时逃逸了局部变量`'static_array'`的引用
    return null;
}//.1

@safe
A bar()
{
    int[1024] static_array;
    return new A(static_array[]);
}//.2

@safe
void main()
{
    auto a = bar();
    writeln(a.data); // OK, 但写的是垃圾
}

所以编译器在foo()中检测逃逸,而在bar()中没有,这不对.
是否可区分切片是来自动态数组还是静态数组?

编译器可用-dip1000开关来检测它.
为了调试?也许找到栈边界,检查地址是否在栈中?

.1编译器来说是很简单的.
.2需要更深层次分析代码.是的,传递了切片构造器,但是不知道构造器是否会存储该切片,或只是使用它.即使下面代码是安全的,但编译器不能检测:

class A
{
    @safe
    this(int[] inData)
    {
        data = someCondition() ? new int[42] : inData; // (1)
        // ...
        if (someOtherCondition()) {
            data = null;                               // (2)
        }
    }
    // ...
}

(1)根据someCondition(),确定是否使用inData,可能根据程序中的someCondition(),根本不会调用bar().
(2)构造器退出后,根据someOtherCondition(),数据可能不会引用"static_array"
编译器很难看穿.(@live也许有帮助.)此外,"单独编译"使它看不穿函数边界.
此外,不希望编译器强制复制所有栈变量.

D的安全模型一样.在@安全代码中,D拒绝编译器不确定内存安全的内容.然而,与Rust中不同的是,@安全在D中不是默认的,因此要手动标记.
@safe``删除破坏内存.@live正在通过跟踪数据活跃度来改善.
@安全的目标是确保在@安全代码中不能破坏内存,仅在@系统@信任中间断出现,如果文档没说不清楚,就是文档的问题.
但是,存在一些需要重大更改才能@安全已知的问题,并且为了使现有代码更易迁移,这些更改隐藏在dip1000下,因此实践中,如果不带-dip1000的使用@安全,可能会遇见危及内存安全编译器错误.
你的示例,就是这样.不带-dip1000,应禁止@安全代码中切片栈分配的静态数组,但由于存在漏洞,编译器允许它,因此应由-dip1000开关修复该错误.

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