Safe mode in D?

Maxim Fomin maxim at maxim-fomin.ru
Fri Oct 18 00:30:44 PDT 2013


On Friday, 18 October 2013 at 07:04:39 UTC, Maxim Fomin wrote:
> On Thursday, 17 October 2013 at 23:18:21 UTC, DDD wrote:
>>
>>
>> I tried this code and the compiler allowed it (runtime I get 
>> object.Error: Access Violation). What am I doing wrong?
>>
>> Thanks I didn't notice
>>
>> @safe
>> import std.stdio;
>> class A {
>> 	int x  = 1;
>> }
>> @safe void main() {
>> 	A a;
>> 	a.x=9;
>> }
>
> Yes, compiler allows it. But this is basic case.
>
> Here is D' Bugs Hall Of Fame (collection of memory errors, type 
> system breakages and other cases to shoot your foot provided by 
> bugzilla issues, me and other people) :
>

Moar :)

// ---- Case 6. UDA bugs - purity loophole ---- //
// discovered by Timon Gehr
import std.stdio;
int x;
@(write(x++),writeln()) void foo(){}

@safe pure void main(){
     __traits(getAttributes, foo);
     __traits(getAttributes, foo)[0];
     __traits(getAttributes, foo)[0];
     //write(x++), writeln(); // Error: pure function cannot ...
}

// ---- Case 7. Writing to typeinfo in purity code ---- //

import core.stdc.string, std.stdio;

pure void rtSetDefaultHeapInitializer(T)(T value) if (is(T == 
class))
{
	byte[] init_mem = new byte[T.classinfo.init.length];
	memcpy(init_mem.ptr, cast(byte*)value, T.classinfo.init.length);
	T.classinfo.init = init_mem;
}

class A
{
    int a;
}

int foo() pure
{
    A a = new A;
    a.a++;
    rtSetDefaultHeapInitializer(a);
    return a.a;
}

void main()
{
    writeln(foo, foo, foo);
}

// ---- Case 8. Escaping references and memory bugs ---- //
import std.stdio;

alias long[100] T;

T delegate() dg;

//ref T foo(ref T i) @safe
void foo(ref T i) @safe
{
    dg = { return i; } ;
    //return i;
}

//ref T bar()
void bar() @safe
{
    T i = 1;
    //return foo(i);
    foo(i);
}

void rewrite_stack() @safe
{
    T tmp = -1;
}

void main()
{
    //T i = bar();
    bar();
    rewrite_stack();
    writeln(dg());
}

This is not so obvious as previous.

// ---- Case 9. Escaping static arrays. ---- //

import std.stdio;

class A
{
    int[] data;
    ~this()
    {
       writeln(data);
    }
}

void foo(int[] a) @safe
{
    A x = new A;
    x.data = a;
}

void main() @safe
{
    int[4] y;
    foo(y);
}

// ---- Case 10. Mutating immutable ---- //
import std.stdio;

immutable int i;
immutable int *ptr;

static this()
{
    ++i, ptr = &i;
}

void main()
{
    foreach (i; 0 .. 10)
    {
       _staticCtor1();
       writeln(i);
    }
}

(Basically problem here is that nether dmd nor linker cares about 
symbol protection)

// --- Case 11. Writing to global though pure functions ---- //

int a;

pure foo(ref int a = a) { ++a; }

void main() pure
{
    foo();
}

// ---- Case 12. Breaking immutable via pure ---- //

import std.stdio;
import core.memory;

class A
{
    int *ptr;
    ~this()
    {
       (*ptr)++;
    }
}

pure foo()
{
    A a = new A;
    int* ptr = new int;
    a.ptr = ptr;
    a = null;
    return ptr;
}

void main()
{
    immutable int* ptr = foo();
    writeln(*ptr); // 0
    GC.collect();
    writeln(*ptr); // 1
}

The latest bug is nice, because after 2.063 Kenji has fixed the 
language, improving consistency of calling immutable/const 
qualified constructors, but allowed to cast return value of pure 
function to immutable because there was belief that inside purity 
function value cannot escape. Such ideom was advertised several 
times in this newsgroups. It appears that idea is not reliable.

Probably there are other cases.

tl;dr do not take into account D' type system and safety 
seriously.


More information about the Digitalmars-d mailing list