P99
p99_checkargs.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the author and copyright holder for this work is */
5 /* (C) copyright 2012 Jens Gustedt, INRIA, France */
6 /* */
7 /* This file is free software; it is part of the P99 project. */
8 /* */
9 /* Licensed under the Apache License, Version 2.0 (the "License"); */
10 /* you may not use this file except in compliance with the License. */
11 /* You may obtain a copy of the License at */
12 /* */
13 /* http://www.apache.org/licenses/LICENSE-2.0 */
14 /* */
15 /* Unless required by applicable law or agreed to in writing, software */
16 /* distributed under the License is distributed on an "AS IS" BASIS, */
17 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
18 /* See the License for the specific language governing permissions and */
19 /* limitations under the License. */
20 /* */
21 #ifndef P99_CHECKARGS_H_
22 # define P99_CHECKARGS_H_
23 
30 #include "p99_constraint.h"
31 #include "p99_map.h"
32 #include "p99_enum.h"
33 #include "p99_type.h"
34 #include P99_ADVANCE_ID
35 
36 #define P00_CA_ASIZE(X) size_t const P99_PASTE2(p00_ca_asize_, X)
37 #define P00_CA_ASIZES(N, ...) P99_SEQ(P00_CA_ASIZE, __VA_ARGS__)
38 
39 #define P00_CA_PSIZE(X) size_t const P99_PASTE2(p00_ca_psize_, X)
40 #define P00_CA_PSIZES(N, ...) P99_SEQ(P00_CA_PSIZE, __VA_ARGS__)
41 
42 #define P00_CA_FSIZE(_0, X, _2) size_t P99_PASTE2(p00_ca_fsize_, X); P99_UNUSED(P99_PASTE2(p00_ca_fsize_, X))
43 #define P00_CA_FSIZES(N, ...) P99_FOR(, P99_NARG(__VA_ARGS__), P00_SEP, P00_CA_FSIZE, __VA_ARGS__)
44 
45 #define P00_CA_TYPEDEF(X) typedef X
46 #define P00_CA_TYPEDEFS(N, ...) P99_SEP(P00_CA_TYPEDEF, P99_REVS(__VA_ARGS__))
47 
48 #define P00_CA_FSIZEOF(_0, X, _2) P99_PASTE2(p00_ca_fsize_, X) = sizeof(X)
49 #define P00_CA_FSIZEOFS(N, ...) P99_FOR(, N, P00_SEP, P00_CA_FSIZEOF, __VA_ARGS__)
50 
51 #define P00_CA_MANGLE_JOIN(X) _, X
52 #define P00_CA_MANGLE_LIST_(...) P99_PASTE(__VA_ARGS__)
53 #define P00_CA_MANGLE_LIST(...) P00_CA_MANGLE_LIST_(P99_SEQ(P00_CA_MANGLE_JOIN, __VA_ARGS__))
54 
55 #define P00_CA_MANGLE(NAME, ACHECKS, PCHECKS) \
56 P99_PASTE(p00_ca_, \
57  NAME, \
58  _p00_achecks, \
59  P00_CA_MANGLE_LIST ACHECKS, \
60  _p00_pchecks, \
61  P00_CA_MANGLE_LIST PCHECKS \
62  )
63 
64 P99_CONSTANT(int, P00_CA_CHECK_BUFFLEN, 512);
65 
66 #define P00_CA_ACHECK_(P, X) \
67 if (P99_LIKELY(X)) { \
68  if (P99_UNLIKELY \
69  ( \
70  /* passing in a larger array is ok */ \
71  (P99_PASTE2(p00_ca_fsize_, X) > P99_PASTE2(p00_ca_asize_, P)) \
72  ) \
73  ) { \
74  char buf[P00_CA_CHECK_BUFFLEN]; \
75  snprintf(buf, P00_CA_CHECK_BUFFLEN - 1, \
76  "%s, call from %s, size of parameter " P99_STRINGIFY(X) " is %zu instead of %zu", \
77  p00_proto, \
78  p00_call, \
79  P99_PASTE2(p00_ca_asize_, P), \
80  P99_PASTE2(p00_ca_fsize_, X) \
81  ); \
82  P99_CONSTRAINT_TRIGGER(ERANGE, buf); \
83  } \
84  } else { \
85  char buf[P00_CA_CHECK_BUFFLEN]; \
86  snprintf(buf, P00_CA_CHECK_BUFFLEN - 1, \
87  "%s, call from %s, parameter " P99_STRINGIFY(X) ", is null pointer", \
88  p00_proto, \
89  p00_call \
90  ); \
91  P99_CONSTRAINT_TRIGGER(ENOMEM, buf); \
92  }
93 
94 #define P00_CA_ACHECK(LIST, X, _2) P00_CA_ACHECK_(X, P99_CHS(X, P00_ROBUST LIST))
95 
96 #define P00_CA_ACHECKS(LIST, N, ...) P99_FOR(LIST, P99_NARG(__VA_ARGS__), P00_SEP, P00_CA_ACHECK, __VA_ARGS__)
97 
98 #define P00_CA_PCHECK_(P, X, I) \
99 if (P99_LIKELY(X)) { \
100  size_t const P99_PASTE2(p00_ca_lsize_, I) = sizeof((X)[0]); \
101  if (P99_UNLIKELY \
102  ( \
103  (P99_PASTE2(p00_ca_lsize_, I) != P99_PASTE2(p00_ca_psize_, P)) \
104  ) \
105  ) { \
106  char buf[P00_CA_CHECK_BUFFLEN]; \
107  snprintf(buf, P00_CA_CHECK_BUFFLEN - 1, \
108  "%s, call from %s, sizeof " P99_STRINGIFY(X) "[0] is %zu instead of %zu", \
109  p00_proto, \
110  p00_call, \
111  P99_PASTE2(p00_ca_psize_, P), \
112  P99_PASTE2(p00_ca_lsize_, I) \
113  ); \
114  P99_CONSTRAINT_TRIGGER(ERANGE, buf); \
115  } \
116  } else { \
117  char buf[P00_CA_CHECK_BUFFLEN]; \
118  snprintf(buf, P00_CA_CHECK_BUFFLEN - 1, \
119  "%s, call from %s, parameter " P99_STRINGIFY(X) " is null pointer", \
120  p00_proto, \
121  p00_call \
122  ); \
123  P99_CONSTRAINT_TRIGGER(ENOMEM, buf); \
124  }
125 
126 #define P00_CA_PCHECK(LIST, X, I) P00_CA_PCHECK_(X, P99_CHS(X, P00_ROBUST LIST), I)
127 
128 
129 #define P00_CA_PCHECKS(LIST, N, ...) P99_FOR(LIST, P99_NARG(__VA_ARGS__), P00_SEP, P00_CA_PCHECK, __VA_ARGS__)
130 
131 
132 #define P00_CA_WRAP_DECLARE(NAME, RET, TYPES, STYPES, VARS, ACHECKS, PCHECKS) \
133  /* clang tries to be helpful here, but we know better */ \
134 P99_IF_COMPILER(CLANG, GCC diagnostic push) \
135  /*P99_IF_COMPILER(CLANG, GCC diagnostic ignored "-Wsizeof-array-argument")*/ \
136 inline \
137 RET P00_CA_MANGLE(NAME, ACHECKS, PCHECKS) \
138  ( \
139  char const* p00_call, \
140  P99_IF_EMPTY ACHECKS()(P00_CA_ASIZES(P99_NARG ACHECKS, P00_ROBUST ACHECKS),) \
141  P99_IF_EMPTY PCHECKS()(P00_CA_PSIZES(P99_NARG PCHECKS, P00_ROBUST PCHECKS),) \
142  P00_ROBUST TYPES) { \
143  char const*const p00_proto = P99_STRINGIFY(NAME) STYPES; \
144  P99_UNUSED(p00_proto); \
145  P99_IF_EMPTY ACHECKS() \
146  ( \
147  P00_CA_FSIZES(P99_NARG VARS, P00_ROBUST VARS); \
148  { \
149  P00_CA_TYPEDEFS(P99_NARG TYPES, P00_ROBUST TYPES); \
150  P00_CA_FSIZEOFS(P99_NARG VARS, P00_ROBUST VARS); \
151  } \
152  P00_CA_ACHECKS(VARS, P99_NARG ACHECKS, P00_ROBUST ACHECKS); \
153  ) \
154  P00_CA_PCHECKS(VARS, P99_NARG PCHECKS, P00_ROBUST PCHECKS); \
155  /* Do a type check without re-declaring the function */ \
156  RET (*P99_PASTE2(p00_ca_ft_, NAME)) TYPES = NAME; \
157  P99_UNUSED(P99_PASTE2(p00_ca_ft_, NAME)); \
158  P99_IF_EQ_1(P99_IS_TOK(void, RET))()(return) \
159  NAME VARS; \
160 } \
161 P99_IF_COMPILER(CLANG, GCC diagnostic pop) \
162 P99_MACRO_END(P00_CA_WRAP_RET_DECLARE)
163 
164 #define P00_CA_WRAP_DECLARE2(NAME, RET, TYPES, STYPES, VARS, ACHECKS, PCHECKS) \
165 P00_CA_WRAP_DECLARE(NAME, RET, TYPES, STYPES, VARS, \
166  P99_IF_EMPTY ACHECKS(())(ACHECKS), \
167  P99_IF_EMPTY PCHECKS(())(PCHECKS))
168 
169 
170 #define P99_CA_WRAP_DECLARE(NAME, RET, TYPES, VARS, ...) \
171 P99_IF_LT(P99_NARG(__VA_ARGS__), 2) \
172 (P00_CA_WRAP_DECLARE(NAME, RET, TYPES, #TYPES, VARS, __VA_ARGS__, __VA_ARGS__)) \
173 (P00_CA_WRAP_DECLARE(NAME, RET, TYPES, #TYPES, VARS, __VA_ARGS__))
174 
175 #define P00_CA_WRAP_DEFINE(NAME, RET, TYPES, VARS, ACHECKS, PCHECKS) \
176  P00_INSTANTIATE(RET, \
177  P00_CA_MANGLE(NAME, ACHECKS, PCHECKS), \
178  char const* p00_call, \
179  P99_IF_EMPTY ACHECKS()(P00_CA_ASIZES(P99_NARG ACHECKS, P00_ROBUST ACHECKS),) \
180  P99_IF_EMPTY PCHECKS()(P00_CA_PSIZES(P99_NARG PCHECKS, P00_ROBUST PCHECKS),) \
181  P00_ROBUST TYPES)
182 
183 #define P00_CA_WRAP_DEFINE2(NAME, RET, TYPES, VARS, ACHECKS, PCHECKS) \
184 P00_CA_WRAP_DEFINE(NAME, RET, TYPES, VARS, \
185  P99_IF_EMPTY ACHECKS(())(ACHECKS), \
186  P99_IF_EMPTY PCHECKS(())(PCHECKS))
187 
188 #define P99_CA_WRAP_DEFINE(NAME, RET, TYPES, VARS, ...) \
189 P99_IF_LT(P99_NARG(__VA_ARGS__), 2) \
190 (P00_CA_WRAP_DEFINE(NAME, RET, TYPES, VARS, __VA_ARGS__, __VA_ARGS__)) \
191 (P00_CA_WRAP_DEFINE(NAME, RET, TYPES, VARS, __VA_ARGS__))
192 
193 #define P00_CA_SIZEOF(LIST, X, _2) sizeof(P99_CHS(X, P00_ROBUST LIST))
194 #define P00_CA_SIZEOFS(LIST, N, ...) P99_FOR(LIST, N, P00_SEQ, P00_CA_SIZEOF, __VA_ARGS__)
195 
196 #define P00_CA_PSIZEOF(LIST, X, _2) sizeof(P99_CHS(X, P00_ROBUST LIST)[0])
197 #define P00_CA_PSIZEOFS(LIST, N, ...) P99_FOR(LIST, N, P00_SEQ, P00_CA_PSIZEOF, __VA_ARGS__)
198 
199 
200 #ifndef P99_NO_CHECKARGS
201 P00_DOCUMENT_PERMITTED_ARGUMENT(P99_CA_CALL, 1)
202 P00_DOCUMENT_PERMITTED_ARGUMENT(P99_CA_CALL, 2)
203 P00_DOCUMENT_PERMITTED_ARGUMENT(P99_CA_CALL, 3)
204 P00_DOCUMENT_PERMITTED_ARGUMENT(P99_CA_CALL, 4)
205 P00_DOCUMENT_PERMITTED_ARGUMENT(P99_CA_CALL, 5)
206 #define P99_CA_CALL(NAME, ACHECKS, PCHECKS, ...) \
207 P00_CA_MANGLE(NAME, ACHECKS, PCHECKS) \
208 ( \
209  __FILE__ ":" P99_STRINGIFY(__LINE__) ": " \
210  P99_STRINGIFY(NAME) "(" #__VA_ARGS__ ")", \
211  P99_IF_EMPTY ACHECKS()(P00_CA_SIZEOFS((__VA_ARGS__), P99_NARG ACHECKS, P00_ROBUST ACHECKS),) \
212  P99_IF_EMPTY PCHECKS()(P00_CA_PSIZEOFS((__VA_ARGS__), P99_NARG PCHECKS, P00_ROBUST PCHECKS),) \
213  __VA_ARGS__ \
214 )
215 #else
216 #define P99_CA_CALL(NAME, ACHECKS, PCHECKS, ...) NAME(__VA_ARGS__)
217 #endif
218 
219 #endif
p99_type.h
P99_CONSTANT
#define P99_CONSTANT(T, NAME, INIT)
define a compile time constant NAME of type T with value INIT
Definition: p99_enum.h:258
p99_map.h
macros to produce lists of statements or declarations.
P99_CA_CALL
#define P99_CA_CALL(NAME, ACHECKS, PCHECKS,...)
Definition: p99_checkargs.h:206
p99_enum.h
p99_constraint.h