VirtualBox

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

Last change on this file since 106724 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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