// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include #include #include "go.h" /* * look for * unsafe.Sizeof * unsafe.Offsetof * unsafe.Alignof * rewrite with a constant */ Node* unsafenmagic(Node *nn) { Node *r, *n, *base, *r1; Sym *s; Type *t, *tr; vlong v; Val val; Node *fn; NodeList *args; fn = nn->left; args = nn->list; if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S) goto no; if(s->pkg != unsafepkg) goto no; if(args == nil) { yyerror("missing argument for %S", s); goto no; } r = args->n; if(strcmp(s->name, "Sizeof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; dowidth(tr); v = tr->width; goto yes; } if(strcmp(s->name, "Offsetof") == 0) { // must be a selector. if(r->op != OXDOT) goto bad; // Remember base of selector to find it back after dot insertion. // Since r->left may be mutated by typechecking, check it explicitly // first to track it correctly. typecheck(&r->left, Erv); base = r->left; typecheck(&r, Erv); switch(r->op) { case ODOT: case ODOTPTR: break; case OCALLPART: yyerror("invalid expression %N: argument is a method value", nn); v = 0; goto ret; default: goto bad; } v = 0; // add offsets for inserted dots. for(r1=r; r1->left!=base; r1=r1->left) { switch(r1->op) { case ODOT: v += r1->xoffset; break; case ODOTPTR: yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left); goto ret; default: dump("unsafenmagic", r); fatal("impossible %#O node after dot insertion", r1->op); goto bad; } } v += r1->xoffset; goto yes; } if(strcmp(s->name, "Alignof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; // make struct { byte; T; } t = typ(TSTRUCT); t->type = typ(TFIELD); t->type->type = types[TUINT8]; t->type->down = typ(TFIELD); t->type->down->type = tr; // compute struct widths dowidth(t); // the offset of T is its required alignment v = t->type->down->width; goto yes; } no: return N; bad: yyerror("invalid expression %N", nn); v = 0; goto ret; yes: if(args->next != nil) yyerror("extra arguments for %S", s); ret: // any side effects disappear; ignore init val.ctype = CTINT; val.u.xval = mal(sizeof(*n->val.u.xval)); mpmovecfix(val.u.xval, v); n = nod(OLITERAL, N, N); n->orig = nn; n->val = val; n->type = types[TUINTPTR]; nn->type = types[TUINTPTR]; return n; } int isunsafebuiltin(Node *n) { if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg) return 0; if(strcmp(n->sym->name, "Sizeof") == 0) return 1; if(strcmp(n->sym->name, "Offsetof") == 0) return 1; if(strcmp(n->sym->name, "Alignof") == 0) return 1; return 0; }