Commit fe2ccb53 authored by Russ Cox's avatar Russ Cox

cc: add two new #pragma varargck

#pragma varargck countpos f 1
says that the first argument to f is
the count of variadic arguments that follow.

#pragma varargck type f t
says that t is one of the allowed types for
a variadic argument to f.
(can be repeated)

combined, these can be used to check the
runtime.stdcall functions in the windows port
or in any other port that needs a vararg list of
uintptrs even on a 64-bit platform (where it is
very easy to pass a less-than-uintptr in the ...).

demo:

typedef unsigned int uintptr;

#pragma varargck countpos f 1
#pragma varargck type f uintptr
#pragma varargck type f void*

int f(int count, ...);

void *v;
char *p;

void
main(void)
{
        f(1, v);  // ok
        f(1, main);  // ok
        f(1, p);  // ok
        f(2, v, v);  // ok

        f(2, v);  // found 1 argument after count 2
        f(1, 'a');  // invalid type INT in call to f
        f(1, 0);  // invalid type INT in call to f
}

R=ken, r, alex.brainman
CC=golang-dev
https://golang.org/cl/4634103
parent f7115327
...@@ -56,7 +56,9 @@ struct Tname ...@@ -56,7 +56,9 @@ struct Tname
{ {
char* name; char* name;
int param; int param;
int count;
Tname* link; Tname* link;
Tprot* prot;
}; };
static Type* indchar; static Type* indchar;
...@@ -131,8 +133,8 @@ getflag(char *s) ...@@ -131,8 +133,8 @@ getflag(char *s)
return flag; return flag;
} }
void static void
newprot(Sym *m, Type *t, char *s) newprot(Sym *m, Type *t, char *s, Tprot **prot)
{ {
Bits flag; Bits flag;
Tprot *l; Tprot *l;
...@@ -142,32 +144,37 @@ newprot(Sym *m, Type *t, char *s) ...@@ -142,32 +144,37 @@ newprot(Sym *m, Type *t, char *s)
return; return;
} }
flag = getflag(s); flag = getflag(s);
for(l=tprot; l; l=l->link) for(l=*prot; l; l=l->link)
if(beq(flag, l->flag) && sametype(t, l->type)) if(beq(flag, l->flag) && sametype(t, l->type))
return; return;
l = alloc(sizeof(*l)); l = alloc(sizeof(*l));
l->type = t; l->type = t;
l->flag = flag; l->flag = flag;
l->link = tprot; l->link = *prot;
tprot = l; *prot = l;
} }
void static Tname*
newname(char *s, int p) newname(char *s, int p, int count)
{ {
Tname *l; Tname *l;
for(l=tname; l; l=l->link) for(l=tname; l; l=l->link)
if(strcmp(l->name, s) == 0) { if(strcmp(l->name, s) == 0) {
if(l->param != p) if(p >= 0 && l->param != p)
yyerror("vargck %s already defined\n", s); yyerror("vargck %s already defined\n", s);
return; return l;
} }
if(p < 0)
return nil;
l = alloc(sizeof(*l)); l = alloc(sizeof(*l));
l->name = s; l->name = s;
l->param = p; l->param = p;
l->link = tname; l->link = tname;
l->count = count;
tname = l; tname = l;
return l;
} }
void void
...@@ -234,6 +241,7 @@ pragvararg(void) ...@@ -234,6 +241,7 @@ pragvararg(void)
int n, c; int n, c;
char *t; char *t;
Type *ty; Type *ty;
Tname *l;
if(!debug['F']) if(!debug['F'])
goto out; goto out;
...@@ -244,6 +252,8 @@ pragvararg(void) ...@@ -244,6 +252,8 @@ pragvararg(void)
goto cktype; goto cktype;
if(s && strcmp(s->name, "flag") == 0) if(s && strcmp(s->name, "flag") == 0)
goto ckflag; goto ckflag;
if(s && strcmp(s->name, "countpos") == 0)
goto ckcount;
yyerror("syntax in #pragma varargck"); yyerror("syntax in #pragma varargck");
goto out; goto out;
...@@ -255,7 +265,18 @@ ckpos: ...@@ -255,7 +265,18 @@ ckpos:
n = getnsn(); n = getnsn();
if(n < 0) if(n < 0)
goto bad; goto bad;
newname(s->name, n); newname(s->name, n, 0);
goto out;
ckcount:
/*#pragma varargck countpos name 2*/
s = getsym();
if(s == S)
goto bad;
n = getnsn();
if(n < 0)
goto bad;
newname(s->name, 0, n);
goto out; goto out;
ckflag: ckflag:
...@@ -276,6 +297,25 @@ ckflag: ...@@ -276,6 +297,25 @@ ckflag:
goto out; goto out;
cktype: cktype:
c = getnsc();
unget(c);
if(c != '"') {
/*#pragma varargck type name int*/
s = getsym();
if(s == S)
goto bad;
l = newname(s->name, -1, -1);
s = getsym();
if(s == S)
goto bad;
ty = s->type;
while((c = getnsc()) == '*')
ty = typ(TIND, ty);
unget(c);
newprot(s, ty, "a", &l->prot);
goto out;
}
/*#pragma varargck type O int*/ /*#pragma varargck type O int*/
t = getquoted(); t = getquoted();
if(t == nil) if(t == nil)
...@@ -287,7 +327,7 @@ cktype: ...@@ -287,7 +327,7 @@ cktype:
while((c = getnsc()) == '*') while((c = getnsc()) == '*')
ty = typ(TIND, ty); ty = typ(TIND, ty);
unget(c); unget(c);
newprot(s, ty, t); newprot(s, ty, t, &tprot);
goto out; goto out;
bad: bad:
...@@ -384,7 +424,8 @@ dpcheck(Node *n) ...@@ -384,7 +424,8 @@ dpcheck(Node *n)
char *s; char *s;
Node *a, *b; Node *a, *b;
Tname *l; Tname *l;
int i; Tprot *tl;
int i, j;
if(n == Z) if(n == Z)
return; return;
...@@ -398,20 +439,76 @@ dpcheck(Node *n) ...@@ -398,20 +439,76 @@ dpcheck(Node *n)
if(l == 0) if(l == 0)
return; return;
if(l->count > 0) {
// fetch count, then check remaining length
i = l->count;
a = nil;
b = n->right;
while(i > 0) {
b = nextarg(b, &a);
i--;
}
if(a == Z) {
diag(n, "can't find count arg");
return;
}
if(a->op != OCONST || !typechl[a->type->etype]) {
diag(n, "count is invalid constant");
return;
}
j = a->vconst;
i = 0;
while(b != Z) {
b = nextarg(b, &a);
i++;
}
if(i != j)
diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
}
if(l->prot != nil) {
// check that all arguments after param or count
// are listed in type list.
i = l->count;
if(i == 0)
i = l->param;
if(i == 0)
return;
a = nil;
b = n->right;
while(i > 0) {
b = nextarg(b, &a);
i--;
}
if(a == Z) {
diag(n, "can't find count/param arg");
return;
}
while(b != Z) {
b = nextarg(b, &a);
for(tl=l->prot; tl; tl=tl->link)
if(sametype(a->type, tl->type))
break;
if(tl == nil)
diag(a, "invalid type %T in call to %s", a->type, s);
}
}
if(l->param <= 0)
return;
i = l->param; i = l->param;
a = nil; a = nil;
b = n->right; b = n->right;
a = Z;
while(i > 0) { while(i > 0) {
b = nextarg(b, &a); b = nextarg(b, &a);
i--; i--;
} }
if(a == Z) { if(a == Z) {
warn(n, "cant find format arg"); diag(n, "can't find format arg");
return; return;
} }
if(!sametype(indchar, a->type)) { if(!sametype(indchar, a->type)) {
warn(n, "format arg type %T", a->type); diag(n, "format arg type %T", a->type);
return; return;
} }
if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment