1 2 /* Compiler implementation of the D programming language 3 * Copyright (C) 1999-2019 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 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() < (unsigned)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 */ 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