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