1*627f7eb2Smrg
2*627f7eb2Smrg /* Compiler implementation of the D programming language
3*627f7eb2Smrg * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4*627f7eb2Smrg * written by Walter Bright
5*627f7eb2Smrg * http://www.digitalmars.com
6*627f7eb2Smrg * Distributed under the Boost Software License, Version 1.0.
7*627f7eb2Smrg * http://www.boost.org/LICENSE_1_0.txt
8*627f7eb2Smrg * https://github.com/D-Programming-Language/dmd/blob/master/src/safe.c
9*627f7eb2Smrg */
10*627f7eb2Smrg
11*627f7eb2Smrg #include "mars.h"
12*627f7eb2Smrg #include "expression.h"
13*627f7eb2Smrg #include "scope.h"
14*627f7eb2Smrg #include "aggregate.h"
15*627f7eb2Smrg #include "target.h"
16*627f7eb2Smrg
17*627f7eb2Smrg bool MODimplicitConv(MOD modfrom, MOD modto);
18*627f7eb2Smrg
19*627f7eb2Smrg /*************************************************************
20*627f7eb2Smrg * Check for unsafe access in @safe code:
21*627f7eb2Smrg * 1. read overlapped pointers
22*627f7eb2Smrg * 2. write misaligned pointers
23*627f7eb2Smrg * 3. write overlapped storage classes
24*627f7eb2Smrg * Print error if unsafe.
25*627f7eb2Smrg * Params:
26*627f7eb2Smrg * sc = scope
27*627f7eb2Smrg * e = expression to check
28*627f7eb2Smrg * readonly = if access is read-only
29*627f7eb2Smrg * printmsg = print error message if true
30*627f7eb2Smrg * Returns:
31*627f7eb2Smrg * true if error
32*627f7eb2Smrg */
33*627f7eb2Smrg
checkUnsafeAccess(Scope * sc,Expression * e,bool readonly,bool printmsg)34*627f7eb2Smrg bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg)
35*627f7eb2Smrg {
36*627f7eb2Smrg if (e->op != TOKdotvar)
37*627f7eb2Smrg return false;
38*627f7eb2Smrg DotVarExp *dve = (DotVarExp *)e;
39*627f7eb2Smrg if (VarDeclaration *v = dve->var->isVarDeclaration())
40*627f7eb2Smrg {
41*627f7eb2Smrg if (sc->intypeof || !sc->func || !sc->func->isSafeBypassingInference())
42*627f7eb2Smrg return false;
43*627f7eb2Smrg
44*627f7eb2Smrg AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration();
45*627f7eb2Smrg if (!ad)
46*627f7eb2Smrg return false;
47*627f7eb2Smrg
48*627f7eb2Smrg if (v->overlapped && v->type->hasPointers() && sc->func->setUnsafe())
49*627f7eb2Smrg {
50*627f7eb2Smrg if (printmsg)
51*627f7eb2Smrg e->error("field %s.%s cannot access pointers in @safe code that overlap other fields",
52*627f7eb2Smrg ad->toChars(), v->toChars());
53*627f7eb2Smrg return true;
54*627f7eb2Smrg }
55*627f7eb2Smrg
56*627f7eb2Smrg if (readonly || !e->type->isMutable())
57*627f7eb2Smrg return false;
58*627f7eb2Smrg
59*627f7eb2Smrg if (v->type->hasPointers() && v->type->toBasetype()->ty != Tstruct)
60*627f7eb2Smrg {
61*627f7eb2Smrg if ((ad->type->alignment() < (unsigned)Target::ptrsize ||
62*627f7eb2Smrg (v->offset & (Target::ptrsize - 1))) &&
63*627f7eb2Smrg sc->func->setUnsafe())
64*627f7eb2Smrg {
65*627f7eb2Smrg if (printmsg)
66*627f7eb2Smrg e->error("field %s.%s cannot modify misaligned pointers in @safe code",
67*627f7eb2Smrg ad->toChars(), v->toChars());
68*627f7eb2Smrg return true;
69*627f7eb2Smrg }
70*627f7eb2Smrg }
71*627f7eb2Smrg
72*627f7eb2Smrg if (v->overlapUnsafe && sc->func->setUnsafe())
73*627f7eb2Smrg {
74*627f7eb2Smrg if (printmsg)
75*627f7eb2Smrg e->error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
76*627f7eb2Smrg ad->toChars(), v->toChars());
77*627f7eb2Smrg return true;
78*627f7eb2Smrg }
79*627f7eb2Smrg }
80*627f7eb2Smrg return false;
81*627f7eb2Smrg }
82*627f7eb2Smrg
83*627f7eb2Smrg
84*627f7eb2Smrg /**********************************************
85*627f7eb2Smrg * Determine if it is @safe to cast e from tfrom to tto.
86*627f7eb2Smrg * Params:
87*627f7eb2Smrg * e = expression to be cast
88*627f7eb2Smrg * tfrom = type of e
89*627f7eb2Smrg * tto = type to cast e to
90*627f7eb2Smrg * Returns:
91*627f7eb2Smrg * true if @safe
92*627f7eb2Smrg */
isSafeCast(Expression * e,Type * tfrom,Type * tto)93*627f7eb2Smrg bool isSafeCast(Expression *e, Type *tfrom, Type *tto)
94*627f7eb2Smrg {
95*627f7eb2Smrg // Implicit conversions are always safe
96*627f7eb2Smrg if (tfrom->implicitConvTo(tto))
97*627f7eb2Smrg return true;
98*627f7eb2Smrg
99*627f7eb2Smrg if (!tto->hasPointers())
100*627f7eb2Smrg return true;
101*627f7eb2Smrg
102*627f7eb2Smrg Type *ttob = tto->toBasetype();
103*627f7eb2Smrg
104*627f7eb2Smrg if (ttob->ty == Tclass && tfrom->ty == Tclass)
105*627f7eb2Smrg {
106*627f7eb2Smrg ClassDeclaration *cdfrom = tfrom->isClassHandle();
107*627f7eb2Smrg ClassDeclaration *cdto = ttob->isClassHandle();
108*627f7eb2Smrg
109*627f7eb2Smrg int offset;
110*627f7eb2Smrg if (!cdfrom->isBaseOf(cdto, &offset))
111*627f7eb2Smrg return false;
112*627f7eb2Smrg
113*627f7eb2Smrg if (cdfrom->isCPPinterface() || cdto->isCPPinterface())
114*627f7eb2Smrg return false;
115*627f7eb2Smrg
116*627f7eb2Smrg if (!MODimplicitConv(tfrom->mod, ttob->mod))
117*627f7eb2Smrg return false;
118*627f7eb2Smrg return true;
119*627f7eb2Smrg }
120*627f7eb2Smrg
121*627f7eb2Smrg if (ttob->ty == Tarray && tfrom->ty == Tsarray) // Bugzilla 12502
122*627f7eb2Smrg tfrom = tfrom->nextOf()->arrayOf();
123*627f7eb2Smrg
124*627f7eb2Smrg if ((ttob->ty == Tarray && tfrom->ty == Tarray) ||
125*627f7eb2Smrg (ttob->ty == Tpointer && tfrom->ty == Tpointer))
126*627f7eb2Smrg {
127*627f7eb2Smrg Type *ttobn = ttob->nextOf()->toBasetype();
128*627f7eb2Smrg Type *tfromn = tfrom->nextOf()->toBasetype();
129*627f7eb2Smrg
130*627f7eb2Smrg /* From void[] to anything mutable is unsafe because:
131*627f7eb2Smrg * int*[] api;
132*627f7eb2Smrg * void[] av = api;
133*627f7eb2Smrg * int[] ai = cast(int[]) av;
134*627f7eb2Smrg * ai[0] = 7;
135*627f7eb2Smrg * *api[0] crash!
136*627f7eb2Smrg */
137*627f7eb2Smrg if (tfromn->ty == Tvoid && ttobn->isMutable())
138*627f7eb2Smrg {
139*627f7eb2Smrg if (ttob->ty == Tarray && e->op == TOKarrayliteral)
140*627f7eb2Smrg return true;
141*627f7eb2Smrg return false;
142*627f7eb2Smrg }
143*627f7eb2Smrg
144*627f7eb2Smrg // If the struct is opaque we don't know about the struct members then the cast becomes unsafe
145*627f7eb2Smrg if ((ttobn->ty == Tstruct && !((TypeStruct *)ttobn)->sym->members) ||
146*627f7eb2Smrg (tfromn->ty == Tstruct && !((TypeStruct *)tfromn)->sym->members))
147*627f7eb2Smrg return false;
148*627f7eb2Smrg
149*627f7eb2Smrg const bool frompointers = tfromn->hasPointers();
150*627f7eb2Smrg const bool topointers = ttobn->hasPointers();
151*627f7eb2Smrg
152*627f7eb2Smrg if (frompointers && !topointers && ttobn->isMutable())
153*627f7eb2Smrg return false;
154*627f7eb2Smrg
155*627f7eb2Smrg if (!frompointers && topointers)
156*627f7eb2Smrg return false;
157*627f7eb2Smrg
158*627f7eb2Smrg if (!topointers &&
159*627f7eb2Smrg ttobn->ty != Tfunction && tfromn->ty != Tfunction &&
160*627f7eb2Smrg (ttob->ty == Tarray || ttobn->size() <= tfromn->size()) &&
161*627f7eb2Smrg MODimplicitConv(tfromn->mod, ttobn->mod))
162*627f7eb2Smrg {
163*627f7eb2Smrg return true;
164*627f7eb2Smrg }
165*627f7eb2Smrg }
166*627f7eb2Smrg return false;
167*627f7eb2Smrg }
168*627f7eb2Smrg
169