root/trunk/src/access.c

Revision 751, 10.3 kB (checked in by walter, 2 years ago)

bugzilla 4728 Segfault(toctype.c) by protected/private constructor in an other module

  • Property svn:eol-style set to native
Line 
1 // Copyright (c) 1999-2006 by Digital Mars
2 // All Rights Reserved
3 // written by Walter Bright
4 // http://www.digitalmars.com
5 // License for redistribution is by either the Artistic License
6 // in artistic.txt, or the GNU General Public License in gnu.txt.
7 // See the included readme.txt for details.
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <assert.h>
13
14 #include "root.h"
15 #include "rmem.h"
16
17 #include "enum.h"
18 #include "aggregate.h"
19 #include "init.h"
20 #include "attrib.h"
21 #include "scope.h"
22 #include "id.h"
23 #include "mtype.h"
24 #include "declaration.h"
25 #include "aggregate.h"
26 #include "expression.h"
27 #include "module.h"
28
29 #define LOG 0
30
31 /* Code to do access checks
32  */
33
34 int hasPackageAccess(Scope *sc, Dsymbol *s);
35
36 /****************************************
37  * Return PROT access for Dsymbol smember in this declaration.
38  */
39
40 enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
41 {
42     return PROTpublic;
43 }
44
45 enum PROT StructDeclaration::getAccess(Dsymbol *smember)
46 {
47     enum PROT access_ret = PROTnone;
48
49 #if LOG
50     printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
51         toChars(), smember->toChars());
52 #endif
53     if (smember->toParent() == this)
54     {
55         access_ret = smember->prot();
56     }
57     else if (smember->isDeclaration()->isStatic())
58     {
59         access_ret = smember->prot();
60     }
61     return access_ret;
62 }
63
64 enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
65 {
66     enum PROT access_ret = PROTnone;
67
68 #if LOG
69     printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
70         toChars(), smember->toChars());
71 #endif
72     if (smember->toParent() == this)
73     {
74         access_ret = smember->prot();
75     }
76     else
77     {
78         enum PROT access;
79         int i;
80
81         if (smember->isDeclaration()->isStatic())
82         {
83             access_ret = smember->prot();
84         }
85
86         for (i = 0; i < baseclasses->dim; i++)
87         {   BaseClass *b = (BaseClass *)baseclasses->data[i];
88
89             access = b->base->getAccess(smember);
90             switch (access)
91             {
92                 case PROTnone:
93                     break;
94
95                 case PROTprivate:
96                     access = PROTnone;  // private members of base class not accessible
97                     break;
98
99                 case PROTpackage:
100                 case PROTprotected:
101                 case PROTpublic:
102                 case PROTexport:
103                     // If access is to be tightened
104                     if (b->protection < access)
105                         access = b->protection;
106
107                     // Pick path with loosest access
108                     if (access > access_ret)
109                         access_ret = access;
110                     break;
111
112                 default:
113                     assert(0);
114             }
115         }
116     }
117 #if LOG
118     printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
119         toChars(), smember->toChars(), access_ret);
120 #endif
121     return access_ret;
122 }
123
124 /********************************************************
125  * Helper function for ClassDeclaration::accessCheck()
126  * Returns:
127  *      0       no access
128  *      1       access
129  */
130
131 static int accessCheckX(
132         Dsymbol *smember,
133         Dsymbol *sfunc,
134         AggregateDeclaration *dthis,
135         AggregateDeclaration *cdscope)
136 {
137     assert(dthis);
138
139 #if 0
140     printf("accessCheckX for %s.%s in function %s() in scope %s\n",
141         dthis->toChars(), smember->toChars(),
142         sfunc ? sfunc->toChars() : "NULL",
143         cdscope ? cdscope->toChars() : "NULL");
144 #endif
145     if (dthis->hasPrivateAccess(sfunc) ||
146         dthis->isFriendOf(cdscope))
147     {
148         if (smember->toParent() == dthis)
149             return 1;
150         else
151         {
152             ClassDeclaration *cdthis = dthis->isClassDeclaration();
153             if (cdthis)
154             {
155                 for (int i = 0; i < cdthis->baseclasses->dim; i++)
156                 {   BaseClass *b = (BaseClass *)cdthis->baseclasses->data[i];
157                     enum PROT access;
158
159                     access = b->base->getAccess(smember);
160                     if (access >= PROTprotected ||
161                         accessCheckX(smember, sfunc, b->base, cdscope)
162                        )
163                         return 1;
164
165                 }
166             }
167         }
168     }
169     else
170     {
171         if (smember->toParent() != dthis)
172         {
173             ClassDeclaration *cdthis = dthis->isClassDeclaration();
174             if (cdthis)
175             {
176                 for (int i = 0; i < cdthis->baseclasses->dim; i++)
177                 {   BaseClass *b = (BaseClass *)cdthis->baseclasses->data[i];
178
179                     if (accessCheckX(smember, sfunc, b->base, cdscope))
180                         return 1;
181                 }
182             }
183         }
184     }
185     return 0;
186 }
187
188 /*******************************
189  * Do access check for member of this class, this class being the
190  * type of the 'this' pointer used to access smember.
191  */
192
193 void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
194 {
195     int result;
196
197     FuncDeclaration *f = sc->func;
198     AggregateDeclaration *cdscope = sc->getStructClassScope();
199     enum PROT access;
200
201 #if LOG
202     printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
203         toChars(), smember->toChars(),
204         f ? f->toChars() : NULL,
205         cdscope ? cdscope->toChars() : NULL);
206 #endif
207
208     Dsymbol *smemberparent = smember->toParent();
209     if (!smemberparent || !smemberparent->isAggregateDeclaration())
210     {
211 #if LOG
212         printf("not an aggregate member\n");
213 #endif
214         return;                         // then it is accessible
215     }
216
217     // BUG: should enable this check
218     //assert(smember->parent->isBaseOf(this, NULL));
219
220     if (smemberparent == this)
221     {   enum PROT access = smember->prot();
222
223         result = access >= PROTpublic ||
224                 hasPrivateAccess(f) ||
225                 isFriendOf(cdscope) ||
226                 (access == PROTpackage && hasPackageAccess(sc, this));
227 #if LOG
228         printf("result1 = %d\n", result);
229 #endif
230     }
231     else if ((access = this->getAccess(smember)) >= PROTpublic)
232     {
233         result = 1;
234 #if LOG
235         printf("result2 = %d\n", result);
236 #endif
237     }
238     else if (access == PROTpackage && hasPackageAccess(sc, this))
239     {
240         result = 1;
241 #if LOG
242         printf("result3 = %d\n", result);
243 #endif
244     }
245     else
246     {
247         result = accessCheckX(smember, f, this, cdscope);
248 #if LOG
249         printf("result4 = %d\n", result);
250 #endif
251     }
252     if (!result)
253     {
254         error(loc, "member %s is not accessible", smember->toChars());
255     }
256 }
257
258 /****************************************
259  * Determine if this is the same or friend of cd.
260  */
261
262 int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
263 {
264 #if LOG
265     printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
266 #endif
267     if (this == cd)
268         return 1;
269
270     // Friends if both are in the same module
271     //if (toParent() == cd->toParent())
272     if (cd && getModule() == cd->getModule())
273     {
274 #if LOG
275         printf("\tin same module\n");
276 #endif
277         return 1;
278     }
279
280 #if LOG
281     printf("\tnot friend\n");
282 #endif
283     return 0;
284 }
285
286 /****************************************
287  * Determine if scope sc has package level access to s.
288  */
289
290 int hasPackageAccess(Scope *sc, Dsymbol *s)
291 {
292 #if LOG
293     printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
294 #endif
295
296     for (; s; s = s->parent)
297     {
298         if (s->isPackage() && !s->isModule())
299             break;
300     }
301 #if LOG
302     if (s)
303         printf("\tthis is in package '%s'\n", s->toChars());
304 #endif
305
306     if (s && s == sc->module->parent)
307     {
308 #if LOG
309         printf("\ts is in same package as sc\n");
310 #endif
311         return 1;
312     }
313
314
315 #if LOG
316     printf("\tno package access\n");
317 #endif
318     return 0;
319 }
320
321 /**********************************
322  * Determine if smember has access to private members of this declaration.
323  */
324
325 int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
326 {
327     if (smember)
328     {   AggregateDeclaration *cd = NULL;
329         Dsymbol *smemberparent = smember->toParent();
330         if (smemberparent)
331             cd = smemberparent->isAggregateDeclaration();
332
333 #if LOG
334         printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
335                 toChars(), smember->toChars());
336 #endif
337
338         if (this == cd)         // smember is a member of this class
339         {
340 #if LOG
341             printf("\tyes 1\n");
342 #endif
343             return 1;           // so we get private access
344         }
345
346         // If both are members of the same module, grant access
347         while (1)
348         {   Dsymbol *sp = smember->toParent();
349             if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
350                 smember = sp;
351             else
352                 break;
353         }
354         if (!cd && toParent() == smember->toParent())
355         {
356 #if LOG
357             printf("\tyes 2\n");
358 #endif
359             return 1;
360         }
361         if (!cd && getModule() == smember->getModule())
362         {
363 #if LOG
364             printf("\tyes 3\n");
365 #endif
366             return 1;
367         }
368     }
369 #if LOG
370     printf("\tno\n");
371 #endif
372     return 0;
373 }
374
375 /****************************************
376  * Check access to d for expression e.d
377  */
378
379 void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
380 {
381 #if LOG
382     if (e)
383     {   printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
384         printf("\te->type = %s\n", e->type->toChars());
385     }
386     else
387     {
388         //printf("accessCheck(%s)\n", d->toChars());
389     }
390 #endif
391     if (!e)
392     {
393         if (d->prot() == PROTprivate && d->getModule() != sc->module ||
394             d->prot() == PROTpackage && !hasPackageAccess(sc, d))
395
396             error(loc, "%s %s.%s is not accessible from %s",
397                 d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars());
398     }
399     else if (e->type->ty == Tclass)
400     {   // Do access check
401         ClassDeclaration *cd;
402
403         cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
404 #if 1
405         if (e->op == TOKsuper)
406         {   ClassDeclaration *cd2;
407
408             cd2 = sc->func->toParent()->isClassDeclaration();
409             if (cd2)
410                 cd = cd2;
411         }
412 #endif
413         cd->accessCheck(loc, sc, d);
414     }
415     else if (e->type->ty == Tstruct)
416     {   // Do access check
417         StructDeclaration *cd;
418
419         cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
420         cd->accessCheck(loc, sc, d);
421     }
422 }
Note: See TracBrowser for help on using the browser.