xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/safe.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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