VirtualBox

source: vbox/trunk/src/bldprogs/VBoxCompilerPlugInsCommon.cpp@ 59410

Last change on this file since 59410 was 57498, checked in by vboxsync, 9 years ago

gccplugin: some type check tinkering.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/* $Id: VBoxCompilerPlugInsCommon.cpp 57498 2015-08-21 14:05:16Z vboxsync $ */
2/** @file
3 * VBoxCompilerPlugInsCommon - Code common to the compiler plug-ins.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define VBOX_COMPILER_PLUG_IN_AGNOSTIC
23#include "VBoxCompilerPlugIns.h"
24
25#include <iprt/string.h>
26
27
28/*********************************************************************************************************************************
29* Defined Constants And Macros *
30*********************************************************************************************************************************/
31#define MY_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
32
33/** @name RTSTR_Z_XXX - Size modifiers
34 * @{ */
35#define RTSTR_Z_DEFAULT UINT16_C(0x0001)
36#define RTSTR_Z_LONG UINT16_C(0x0002) /**< l */
37#define RTSTR_Z_LONGLONG UINT16_C(0x0004) /**< ll, L, q. */
38#define RTSTR_Z_HALF UINT16_C(0x0008) /**< h */
39#define RTSTR_Z_HALFHALF UINT16_C(0x0010) /**< hh (internally H) */
40#define RTSTR_Z_SIZE UINT16_C(0x0020) /**< z */
41#define RTSTR_Z_PTRDIFF UINT16_C(0x0040) /**< t */
42#define RTSTR_Z_INTMAX UINT16_C(0x0080) /**< j */
43#define RTSTR_Z_MS_I32 UINT16_C(0x1000) /**< I32 */
44#define RTSTR_Z_MS_I64 UINT16_C(0x2000) /**< I64 */
45#define RTSTR_Z_ALL_INT UINT16_C(0x30fe) /**< short hand for integers. */
46/** @} */
47
48
49/** @name VFMTCHKTYPE_F_XXX - Type flags.
50 * @{ */
51/** Pointers type. */
52#define VFMTCHKTYPE_F_PTR UINT8_C(0x01)
53/** Both const and non-const pointer types. */
54#define VFMTCHKTYPE_F_CPTR (UINT8_C(0x02) | VFMTCHKTYPE_F_PTR)
55/** @} */
56
57/** @name VFMTCHKTYPE_Z_XXX - Special type sizes
58 * @{ */
59#define VFMTCHKTYPE_Z_CHAR UINT8_C(0xe0)
60#define VFMTCHKTYPE_Z_SHORT UINT8_C(0xe1)
61#define VFMTCHKTYPE_Z_INT UINT8_C(0xe2)
62#define VFMTCHKTYPE_Z_LONG UINT8_C(0xe3)
63#define VFMTCHKTYPE_Z_LONGLONG UINT8_C(0xe4)
64#define VFMTCHKTYPE_Z_PTR UINT8_C(0xe5) /**< ASSUMED to be the same for 'void *', 'size_t' and 'ptrdiff_t'. */
65/** @} */
66
67/** @name VFMTCHKTYPE_NM_XXX - Standard C type names.
68 * @{ */
69#define VFMTCHKTYPE_NM_INT "int"
70#define VFMTCHKTYPE_NM_UINT "unsigned int"
71#define VFMTCHKTYPE_NM_LONG "long"
72#define VFMTCHKTYPE_NM_ULONG "unsigned long"
73#define VFMTCHKTYPE_NM_LONGLONG "long long"
74#define VFMTCHKTYPE_NM_ULONGLONG "unsigned long long"
75#define VFMTCHKTYPE_NM_SHORT "short"
76#define VFMTCHKTYPE_NM_USHORT "unsigned short"
77#define VFMTCHKTYPE_NM_CHAR "char"
78#define VFMTCHKTYPE_NM_SCHAR "signed char"
79#define VFMTCHKTYPE_NM_UCHAR "unsigned char"
80/** @} */
81
82
83/** @name VFMTCHKDESC_F_XXX - Format descriptor flags.
84 * @{ */
85#define VFMTCHKDESC_F_NONE UINT32_C(0)
86#define VFMTCHKDESC_F_SIGNED RT_BIT_32(0)
87#define VFMTCHKDESC_F_UNSIGNED RT_BIT_32(1)
88/** @} */
89
90
91/*********************************************************************************************************************************
92* Structures and Typedefs *
93*********************************************************************************************************************************/
94/**
95 * Format check type entry.
96 */
97typedef struct VFMTCHKTYPE
98{
99 /** The format size flag(s). */
100 uint16_t fSize;
101 /** The argument size. */
102 uint8_t cbArg;
103 /** Argument flags (VFMTCHKTYPE_F_XXX). */
104 uint8_t fFlags;
105 /** List of strings with acceptable types, if NULL only check the sizes. */
106 const char *pszzTypeNames;
107} VFMTCHKTYPE;
108/** Pointer to a read only format check type entry. */
109typedef VFMTCHKTYPE const *PCVFMTCHKTYPE;
110
111/** For use as an initializer in VFMTCHKDESK where it indicates that
112 * everything is covered by VFMTCHKDESC::paMoreTypes. Useful for repeating
113 * stuff. */
114#define VFMTCHKTYPE_USE_MORE_TYPES { 0, 0, 0, NULL }
115
116/**
117 * Format type descriptor.
118 */
119typedef struct VFMTCHKDESC
120{
121 /** The format type. */
122 const char *pszType;
123 /** Recognized format flags (RTSTR_F_XXX). */
124 uint16_t fFmtFlags;
125 /** Recognized format sizes (RTSTR_Z_XXX). */
126 uint16_t fFmtSize;
127 /** Flags (VFMTCHKDESC_F_XXX). */
128 uint32_t fFlags;
129 /** Primary type. */
130 VFMTCHKTYPE Type;
131 /** More recognized types (optional). */
132 PCVFMTCHKTYPE paMoreTypes;
133} VFMTCHKDESC;
134typedef VFMTCHKDESC const *PCVFMTCHKDESC;
135
136
137/*********************************************************************************************************************************
138* Global Variables *
139*********************************************************************************************************************************/
140/** Integer type specs for 'x', 'd', 'u', 'i', ++
141 *
142 * @todo RTUINT32U and friends... The whole type matching thing.
143 */
144static VFMTCHKTYPE const g_aIntTypes[] =
145{
146 { RTSTR_Z_DEFAULT, VFMTCHKTYPE_Z_INT, 0, VFMTCHKTYPE_NM_INT "\0" VFMTCHKTYPE_NM_UINT "\0" },
147 { RTSTR_Z_LONG, VFMTCHKTYPE_Z_LONG, 0, VFMTCHKTYPE_NM_LONG "\0" VFMTCHKTYPE_NM_ULONG "\0" },
148 { RTSTR_Z_LONGLONG, VFMTCHKTYPE_Z_LONGLONG, 0, VFMTCHKTYPE_NM_LONGLONG "\0" VFMTCHKTYPE_NM_ULONGLONG "\0" },
149 { RTSTR_Z_HALF, VFMTCHKTYPE_Z_SHORT, 0, VFMTCHKTYPE_NM_SHORT "\0" VFMTCHKTYPE_NM_USHORT "\0" },
150 { RTSTR_Z_HALFHALF, VFMTCHKTYPE_Z_CHAR, 0, VFMTCHKTYPE_NM_SCHAR "\0" VFMTCHKTYPE_NM_UCHAR "\0" VFMTCHKTYPE_NM_CHAR "\0" },
151 { RTSTR_Z_SIZE, VFMTCHKTYPE_Z_PTR, 0, "size_t\0" "RTUINTPTR\0" "RTINTPTR\0" },
152 { RTSTR_Z_PTRDIFF, VFMTCHKTYPE_Z_PTR, 0, "ptrdiff_t\0" "RTUINTPTR\0" "RTINTPTR\0" },
153 { RTSTR_Z_INTMAX, VFMTCHKTYPE_Z_PTR, 0, "uint64_t\0" "int64_t\0" "RTUINT64U\0" VFMTCHKTYPE_NM_LONGLONG "\0" VFMTCHKTYPE_NM_ULONGLONG "\0" },
154 { RTSTR_Z_MS_I32, sizeof(uint32_t), 0, "uint32_t\0" "int32_t\0" "RTUINT32U\0" },
155 { RTSTR_Z_MS_I64, sizeof(uint64_t), 0, "uint64_t\0" "int64_t\0" "RTUINT64U\0" },
156};
157
158/** String type specs for 's', 'ls' and 'Ls'.
159 */
160static VFMTCHKTYPE const g_aStringTypes[] =
161{
162 { RTSTR_Z_DEFAULT, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, VFMTCHKTYPE_NM_CHAR "\0" },
163 { RTSTR_Z_LONG, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, "RTUTF16\0" },
164 { RTSTR_Z_LONGLONG, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, "RTUNICP\0" },
165};
166
167static VFMTCHKDESC const g_aFmtDescs[] =
168{
169 { "s",
170 RTSTR_F_LEFT | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
171 RTSTR_Z_DEFAULT | RTSTR_Z_LONG | RTSTR_Z_LONGLONG,
172 VFMTCHKDESC_F_UNSIGNED,
173 VFMTCHKTYPE_USE_MORE_TYPES,
174 g_aStringTypes
175 },
176 { "x",
177 RTSTR_F_LEFT | RTSTR_F_ZEROPAD | RTSTR_F_SPECIAL | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
178 RTSTR_Z_ALL_INT,
179 VFMTCHKDESC_F_UNSIGNED,
180 VFMTCHKTYPE_USE_MORE_TYPES,
181 g_aIntTypes
182 },
183 { "RX32",
184 RTSTR_F_LEFT | RTSTR_F_ZEROPAD | RTSTR_F_SPECIAL | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
185 RTSTR_Z_ALL_INT,
186 VFMTCHKDESC_F_UNSIGNED,
187 { RTSTR_Z_DEFAULT, sizeof(uint32_t), 0, "uint32_t\0" "int32_t\0" },
188 NULL
189 },
190
191
192
193};
194
195
196/**
197 * Does the actual format string checking.
198 *
199 * @todo Move this to different file common to both GCC and CLANG later.
200 *
201 * @param pState The format string checking state.
202 * @param pszFmt The format string.
203 */
204void MyCheckFormatCString(PVFMTCHKSTATE pState, const char *pszFmt)
205{
206 dprintf("checker2: \"%s\" at %s:%d col %d\n", pszFmt,
207 MYSTATE_FMT_FILE(pState), MYSTATE_FMT_LINE(pState), MYSTATE_FMT_COLUMN(pState));
208 pState->pszFmt = pszFmt;
209
210 unsigned iArg = 0;
211 for (;;)
212 {
213 /*
214 * Skip to the next argument.
215 * Quits the loop with the first char following the '%' in 'ch'.
216 */
217 char ch;
218 for (;;)
219 {
220 ch = *pszFmt++;
221 if (ch == '%')
222 {
223 ch = *pszFmt++;
224 if (ch != '%')
225 break;
226 }
227 else if (ch == '\0')
228 {
229 VFmtChkVerifyEndOfArgs(pState, iArg);
230 return;
231 }
232 }
233 const char * const pszPct = pszFmt - 2;
234
235 /*
236 * Flags
237 */
238 uint32_t fFmtFlags = 0;
239 for (;;)
240 {
241 uint32_t fFlag;
242 switch (ch)
243 {
244 case '#': fFlag = RTSTR_F_SPECIAL; break;
245 case '-': fFlag = RTSTR_F_LEFT; break;
246 case '+': fFlag = RTSTR_F_PLUS; break;
247 case ' ': fFlag = RTSTR_F_BLANK; break;
248 case '0': fFlag = RTSTR_F_ZEROPAD; break;
249 case '\'': fFlag = RTSTR_F_THOUSAND_SEP; break;
250 default: fFlag = 0; break;
251 }
252 if (!fFlag)
253 break;
254 if (fFmtFlags & fFlag)
255 VFmtChkWarnFmt(pState, pszPct, "duplicate flag '%c'", ch);
256 fFmtFlags |= fFlag;
257 ch = *pszFmt++;
258 }
259
260 /*
261 * Width.
262 */
263 int cchWidth = -1;
264 if (MY_ISDIGIT(ch))
265 {
266 cchWidth = ch - '0';
267 while ( (ch = *pszFmt++) != '\0'
268 && MY_ISDIGIT(ch))
269 {
270 cchWidth *= 10;
271 cchWidth += ch - '0';
272 }
273 fFmtFlags |= RTSTR_F_WIDTH;
274 }
275 else if (ch == '*')
276 {
277 VFmtChkRequireIntArg(pState, pszPct, iArg, "width should be an 'int' sized argument");
278 iArg++;
279 cchWidth = 0;
280 fFmtFlags |= RTSTR_F_WIDTH;
281 ch = *pszFmt++;
282 }
283
284 /*
285 * Precision
286 */
287 int cchPrecision = -1;
288 if (ch == '.')
289 {
290 ch = *pszFmt++;
291 if (MY_ISDIGIT(ch))
292 {
293 cchPrecision = ch - '0';
294 while ( (ch = *pszFmt++) != '\0'
295 && MY_ISDIGIT(ch))
296 {
297 cchPrecision *= 10;
298 cchPrecision += ch - '0';
299 }
300 }
301 else if (ch == '*')
302 {
303 VFmtChkRequireIntArg(pState, pszPct, iArg, "precision should be an 'int' sized argument");
304 iArg++;
305 cchPrecision = 0;
306 ch = *pszFmt++;
307 }
308 else
309 VFmtChkErrFmt(pState, pszPct, "Missing precision value, only got the '.'");
310 if (cchPrecision < 0)
311 {
312 VFmtChkErrFmt(pState, pszPct, "Negative precision value: %d", cchPrecision);
313 cchPrecision = 0;
314 }
315 fFmtFlags |= RTSTR_F_PRECISION;
316 }
317
318 /*
319 * Argument size.
320 */
321 uint16_t fFmtSize = RTSTR_Z_DEFAULT;
322 switch (ch)
323 {
324 default:
325 fFmtSize = RTSTR_Z_DEFAULT;
326 break;
327
328 case 'z':
329 fFmtSize = RTSTR_Z_SIZE;
330 ch = *pszFmt++;
331 break;
332 case 'j':
333 fFmtSize = RTSTR_Z_INTMAX;
334 ch = *pszFmt++;
335 case 't':
336 fFmtSize = RTSTR_Z_PTRDIFF;
337 ch = *pszFmt++;
338 break;
339
340 case 'l':
341 fFmtSize = RTSTR_Z_LONG;
342 ch = *pszFmt++;
343 if (ch == 'l')
344 {
345 fFmtSize = RTSTR_Z_LONGLONG;
346 ch = *pszFmt++;
347 }
348 break;
349
350 case 'q': /* Used on BSD platforms. */
351 case 'L':
352 fFmtSize = RTSTR_Z_LONGLONG;
353 ch = *pszFmt++;
354 break;
355
356 case 'h':
357 fFmtSize = RTSTR_Z_HALF;
358 ch = *pszFmt++;
359 if (ch == 'h')
360 {
361 fFmtSize = RTSTR_Z_HALFHALF;
362 ch = *pszFmt++;
363 }
364 break;
365
366 case 'I': /* Used by Win32/64 compilers. */
367 if ( pszFmt[0] == '6'
368 && pszFmt[1] == '4')
369 {
370 pszFmt += 2;
371 fFmtSize = RTSTR_Z_MS_I64;
372 }
373 else if ( pszFmt[0] == '3'
374 && pszFmt[1] == '2')
375 {
376 pszFmt += 2;
377 fFmtSize = RTSTR_Z_MS_I32;
378 }
379 else
380 {
381 VFmtChkErrFmt(pState, pszFmt, "Unknow format type/size/flag 'I%c'", pszFmt[0]);
382 fFmtSize = RTSTR_Z_INTMAX;
383 }
384 ch = *pszFmt++;
385 break;
386 }
387
388 /*
389 * The type.
390 */
391 switch (ch)
392 {
393 /*
394 * Nested extensions.
395 */
396 case 'M': /* replace the format string (not stacked yet). */
397 {
398 if (*pszFmt)
399 VFmtChkErrFmt(pState, pszFmt, "Characters following '%%M' will be ignored");
400 if (fFmtSize != RTSTR_Z_DEFAULT)
401 VFmtChkWarnFmt(pState, pszFmt, "'%%M' does not support any size flags (%#x)", fFmtSize);
402 if (fFmtFlags != 0)
403 VFmtChkWarnFmt(pState, pszFmt, "'%%M' does not support any format flags (%#x)", fFmtFlags);
404 if (VFmtChkRequireStringArg(pState, pszPct, iArg, "'%M' expects a format string"))
405 VFmtChkHandleReplacementFormatString(pState, pszPct, iArg);
406 return;
407 }
408
409 case 'N': /* real nesting. */
410 {
411 if (fFmtSize != RTSTR_Z_DEFAULT)
412 VFmtChkWarnFmt(pState, pszFmt, "'%%N' does not support any size flags (%#x)", fFmtSize);
413 if (fFmtFlags != 0)
414 VFmtChkWarnFmt(pState, pszFmt, "'%%N' does not support any format flags (%#x)", fFmtFlags);
415 VFmtChkRequireStringArg(pState, pszPct, iArg, "'%N' expects a string followed by a va_list pointer");
416 VFmtChkRequireVaListPtrArg(pState, pszPct, iArg + 1, "'%N' expects a string followed by a va_list pointer");
417 iArg += 2;
418 break;
419 }
420
421 default:
422 VFmtChkRequirePresentArg(pState, pszPct, iArg, "Expected argument");
423 iArg++;
424 break;
425 }
426 }
427}
428
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette