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