summaryrefslogtreecommitdiffstats
path: root/src/bldprogs/VBoxCompilerPlugInsCommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bldprogs/VBoxCompilerPlugInsCommon.cpp')
-rw-r--r--src/bldprogs/VBoxCompilerPlugInsCommon.cpp448
1 files changed, 448 insertions, 0 deletions
diff --git a/src/bldprogs/VBoxCompilerPlugInsCommon.cpp b/src/bldprogs/VBoxCompilerPlugInsCommon.cpp
new file mode 100644
index 00000000..11473fd6
--- /dev/null
+++ b/src/bldprogs/VBoxCompilerPlugInsCommon.cpp
@@ -0,0 +1,448 @@
+/* $Id: VBoxCompilerPlugInsCommon.cpp $ */
+/** @file
+ * VBoxCompilerPlugInsCommon - Code common to the compiler plug-ins.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define VBOX_COMPILER_PLUG_IN_AGNOSTIC
+#include "VBoxCompilerPlugIns.h"
+
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define MY_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+
+/** @name RTSTR_Z_XXX - Size modifiers
+ * @{ */
+#define RTSTR_Z_DEFAULT UINT16_C(0x0001)
+#define RTSTR_Z_LONG UINT16_C(0x0002) /**< l */
+#define RTSTR_Z_LONGLONG UINT16_C(0x0004) /**< ll, L, q. */
+#define RTSTR_Z_HALF UINT16_C(0x0008) /**< h */
+#define RTSTR_Z_HALFHALF UINT16_C(0x0010) /**< hh (internally H) */
+#define RTSTR_Z_SIZE UINT16_C(0x0020) /**< z */
+#define RTSTR_Z_PTRDIFF UINT16_C(0x0040) /**< t */
+#define RTSTR_Z_INTMAX UINT16_C(0x0080) /**< j */
+#define RTSTR_Z_MS_I32 UINT16_C(0x1000) /**< I32 */
+#define RTSTR_Z_MS_I64 UINT16_C(0x2000) /**< I64 */
+#define RTSTR_Z_ALL_INT UINT16_C(0x30fe) /**< short hand for integers. */
+/** @} */
+
+
+/** @name VFMTCHKTYPE_F_XXX - Type flags.
+ * @{ */
+/** Pointers type. */
+#define VFMTCHKTYPE_F_PTR UINT8_C(0x01)
+/** Both const and non-const pointer types. */
+#define VFMTCHKTYPE_F_CPTR (UINT8_C(0x02) | VFMTCHKTYPE_F_PTR)
+/** @} */
+
+/** @name VFMTCHKTYPE_Z_XXX - Special type sizes
+ * @{ */
+#define VFMTCHKTYPE_Z_CHAR UINT8_C(0xe0)
+#define VFMTCHKTYPE_Z_SHORT UINT8_C(0xe1)
+#define VFMTCHKTYPE_Z_INT UINT8_C(0xe2)
+#define VFMTCHKTYPE_Z_LONG UINT8_C(0xe3)
+#define VFMTCHKTYPE_Z_LONGLONG UINT8_C(0xe4)
+#define VFMTCHKTYPE_Z_PTR UINT8_C(0xe5) /**< ASSUMED to be the same for 'void *', 'size_t' and 'ptrdiff_t'. */
+/** @} */
+
+/** @name VFMTCHKTYPE_NM_XXX - Standard C type names.
+ * @{ */
+#define VFMTCHKTYPE_NM_INT "int"
+#define VFMTCHKTYPE_NM_UINT "unsigned int"
+#define VFMTCHKTYPE_NM_LONG "long"
+#define VFMTCHKTYPE_NM_ULONG "unsigned long"
+#define VFMTCHKTYPE_NM_LONGLONG "long long"
+#define VFMTCHKTYPE_NM_ULONGLONG "unsigned long long"
+#define VFMTCHKTYPE_NM_SHORT "short"
+#define VFMTCHKTYPE_NM_USHORT "unsigned short"
+#define VFMTCHKTYPE_NM_CHAR "char"
+#define VFMTCHKTYPE_NM_SCHAR "signed char"
+#define VFMTCHKTYPE_NM_UCHAR "unsigned char"
+/** @} */
+
+
+/** @name VFMTCHKDESC_F_XXX - Format descriptor flags.
+ * @{ */
+#define VFMTCHKDESC_F_NONE UINT32_C(0)
+#define VFMTCHKDESC_F_SIGNED RT_BIT_32(0)
+#define VFMTCHKDESC_F_UNSIGNED RT_BIT_32(1)
+/** @} */
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Format check type entry.
+ */
+typedef struct VFMTCHKTYPE
+{
+ /** The format size flag(s). */
+ uint16_t fSize;
+ /** The argument size. */
+ uint8_t cbArg;
+ /** Argument flags (VFMTCHKTYPE_F_XXX). */
+ uint8_t fFlags;
+ /** List of strings with acceptable types, if NULL only check the sizes. */
+ const char *pszzTypeNames;
+} VFMTCHKTYPE;
+/** Pointer to a read only format check type entry. */
+typedef VFMTCHKTYPE const *PCVFMTCHKTYPE;
+
+/** For use as an initializer in VFMTCHKDESK where it indicates that
+ * everything is covered by VFMTCHKDESC::paMoreTypes. Useful for repeating
+ * stuff. */
+#define VFMTCHKTYPE_USE_MORE_TYPES { 0, 0, 0, NULL }
+
+/**
+ * Format type descriptor.
+ */
+typedef struct VFMTCHKDESC
+{
+ /** The format type. */
+ const char *pszType;
+ /** Recognized format flags (RTSTR_F_XXX). */
+ uint16_t fFmtFlags;
+ /** Recognized format sizes (RTSTR_Z_XXX). */
+ uint16_t fFmtSize;
+ /** Flags (VFMTCHKDESC_F_XXX). */
+ uint32_t fFlags;
+ /** Primary type. */
+ VFMTCHKTYPE Type;
+ /** More recognized types (optional). */
+ PCVFMTCHKTYPE paMoreTypes;
+} VFMTCHKDESC;
+typedef VFMTCHKDESC const *PCVFMTCHKDESC;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** Integer type specs for 'x', 'd', 'u', 'i', ++
+ *
+ * @todo RTUINT32U and friends... The whole type matching thing.
+ */
+static VFMTCHKTYPE const g_aIntTypes[] =
+{
+ { RTSTR_Z_DEFAULT, VFMTCHKTYPE_Z_INT, 0, VFMTCHKTYPE_NM_INT "\0" VFMTCHKTYPE_NM_UINT "\0" },
+ { RTSTR_Z_LONG, VFMTCHKTYPE_Z_LONG, 0, VFMTCHKTYPE_NM_LONG "\0" VFMTCHKTYPE_NM_ULONG "\0" },
+ { RTSTR_Z_LONGLONG, VFMTCHKTYPE_Z_LONGLONG, 0, VFMTCHKTYPE_NM_LONGLONG "\0" VFMTCHKTYPE_NM_ULONGLONG "\0" },
+ { RTSTR_Z_HALF, VFMTCHKTYPE_Z_SHORT, 0, VFMTCHKTYPE_NM_SHORT "\0" VFMTCHKTYPE_NM_USHORT "\0" },
+ { RTSTR_Z_HALFHALF, VFMTCHKTYPE_Z_CHAR, 0, VFMTCHKTYPE_NM_SCHAR "\0" VFMTCHKTYPE_NM_UCHAR "\0" VFMTCHKTYPE_NM_CHAR "\0" },
+ { RTSTR_Z_SIZE, VFMTCHKTYPE_Z_PTR, 0, "size_t\0" "RTUINTPTR\0" "RTINTPTR\0" },
+ { RTSTR_Z_PTRDIFF, VFMTCHKTYPE_Z_PTR, 0, "ptrdiff_t\0" "RTUINTPTR\0" "RTINTPTR\0" },
+ { RTSTR_Z_INTMAX, VFMTCHKTYPE_Z_PTR, 0, "uint64_t\0" "int64_t\0" "RTUINT64U\0" VFMTCHKTYPE_NM_LONGLONG "\0" VFMTCHKTYPE_NM_ULONGLONG "\0" },
+ { RTSTR_Z_MS_I32, sizeof(uint32_t), 0, "uint32_t\0" "int32_t\0" "RTUINT32U\0" },
+ { RTSTR_Z_MS_I64, sizeof(uint64_t), 0, "uint64_t\0" "int64_t\0" "RTUINT64U\0" },
+};
+
+/** String type specs for 's', 'ls' and 'Ls'.
+ */
+static VFMTCHKTYPE const g_aStringTypes[] =
+{
+ { RTSTR_Z_DEFAULT, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, VFMTCHKTYPE_NM_CHAR "\0" },
+ { RTSTR_Z_LONG, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, "RTUTF16\0" },
+ { RTSTR_Z_LONGLONG, VFMTCHKTYPE_Z_PTR, VFMTCHKTYPE_F_CPTR, "RTUNICP\0" },
+};
+
+static VFMTCHKDESC const g_aFmtDescs[] =
+{
+ { "s",
+ RTSTR_F_LEFT | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
+ RTSTR_Z_DEFAULT | RTSTR_Z_LONG | RTSTR_Z_LONGLONG,
+ VFMTCHKDESC_F_UNSIGNED,
+ VFMTCHKTYPE_USE_MORE_TYPES,
+ g_aStringTypes
+ },
+ { "x",
+ RTSTR_F_LEFT | RTSTR_F_ZEROPAD | RTSTR_F_SPECIAL | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
+ RTSTR_Z_ALL_INT,
+ VFMTCHKDESC_F_UNSIGNED,
+ VFMTCHKTYPE_USE_MORE_TYPES,
+ g_aIntTypes
+ },
+ { "RX32",
+ RTSTR_F_LEFT | RTSTR_F_ZEROPAD | RTSTR_F_SPECIAL | RTSTR_F_WIDTH | RTSTR_F_PRECISION,
+ RTSTR_Z_ALL_INT,
+ VFMTCHKDESC_F_UNSIGNED,
+ { RTSTR_Z_DEFAULT, sizeof(uint32_t), 0, "uint32_t\0" "int32_t\0" },
+ NULL
+ },
+
+
+
+};
+
+
+/**
+ * Does the actual format string checking.
+ *
+ * @todo Move this to different file common to both GCC and CLANG later.
+ *
+ * @param pState The format string checking state.
+ * @param pszFmt The format string.
+ */
+void MyCheckFormatCString(PVFMTCHKSTATE pState, const char *pszFmt)
+{
+ dprintf("checker2: \"%s\" at %s:%d col %d\n", pszFmt,
+ MYSTATE_FMT_FILE(pState), MYSTATE_FMT_LINE(pState), MYSTATE_FMT_COLUMN(pState));
+ pState->pszFmt = pszFmt;
+
+ unsigned iArg = 0;
+ for (;;)
+ {
+ /*
+ * Skip to the next argument.
+ * Quits the loop with the first char following the '%' in 'ch'.
+ */
+ char ch;
+ for (;;)
+ {
+ ch = *pszFmt++;
+ if (ch == '%')
+ {
+ ch = *pszFmt++;
+ if (ch != '%')
+ break;
+ }
+ else if (ch == '\0')
+ {
+ VFmtChkVerifyEndOfArgs(pState, iArg);
+ return;
+ }
+ }
+ const char * const pszPct = pszFmt - 2;
+
+ /*
+ * Flags
+ */
+ uint32_t fFmtFlags = 0;
+ for (;;)
+ {
+ uint32_t fFlag;
+ switch (ch)
+ {
+ case '#': fFlag = RTSTR_F_SPECIAL; break;
+ case '-': fFlag = RTSTR_F_LEFT; break;
+ case '+': fFlag = RTSTR_F_PLUS; break;
+ case ' ': fFlag = RTSTR_F_BLANK; break;
+ case '0': fFlag = RTSTR_F_ZEROPAD; break;
+ case '\'': fFlag = RTSTR_F_THOUSAND_SEP; break;
+ default: fFlag = 0; break;
+ }
+ if (!fFlag)
+ break;
+ if (fFmtFlags & fFlag)
+ VFmtChkWarnFmt(pState, pszPct, "duplicate flag '%c'", ch);
+ fFmtFlags |= fFlag;
+ ch = *pszFmt++;
+ }
+
+ /*
+ * Width.
+ */
+ int cchWidth = -1;
+ if (MY_ISDIGIT(ch))
+ {
+ cchWidth = ch - '0';
+ while ( (ch = *pszFmt++) != '\0'
+ && MY_ISDIGIT(ch))
+ {
+ cchWidth *= 10;
+ cchWidth += ch - '0';
+ }
+ fFmtFlags |= RTSTR_F_WIDTH;
+ }
+ else if (ch == '*')
+ {
+ VFmtChkRequireIntArg(pState, pszPct, iArg, "width should be an 'int' sized argument");
+ iArg++;
+ cchWidth = 0;
+ fFmtFlags |= RTSTR_F_WIDTH;
+ ch = *pszFmt++;
+ }
+
+ /*
+ * Precision
+ */
+ int cchPrecision = -1;
+ if (ch == '.')
+ {
+ ch = *pszFmt++;
+ if (MY_ISDIGIT(ch))
+ {
+ cchPrecision = ch - '0';
+ while ( (ch = *pszFmt++) != '\0'
+ && MY_ISDIGIT(ch))
+ {
+ cchPrecision *= 10;
+ cchPrecision += ch - '0';
+ }
+ }
+ else if (ch == '*')
+ {
+ VFmtChkRequireIntArg(pState, pszPct, iArg, "precision should be an 'int' sized argument");
+ iArg++;
+ cchPrecision = 0;
+ ch = *pszFmt++;
+ }
+ else
+ VFmtChkErrFmt(pState, pszPct, "Missing precision value, only got the '.'");
+ if (cchPrecision < 0)
+ {
+ VFmtChkErrFmt(pState, pszPct, "Negative precision value: %d", cchPrecision);
+ cchPrecision = 0;
+ }
+ fFmtFlags |= RTSTR_F_PRECISION;
+ }
+
+ /*
+ * Argument size.
+ */
+ uint16_t fFmtSize = RTSTR_Z_DEFAULT;
+ switch (ch)
+ {
+ default:
+ fFmtSize = RTSTR_Z_DEFAULT;
+ break;
+
+ case 'z':
+ fFmtSize = RTSTR_Z_SIZE;
+ ch = *pszFmt++;
+ break;
+ case 'j':
+ fFmtSize = RTSTR_Z_INTMAX;
+ ch = *pszFmt++;
+ break;
+ case 't':
+ fFmtSize = RTSTR_Z_PTRDIFF;
+ ch = *pszFmt++;
+ break;
+
+ case 'l':
+ fFmtSize = RTSTR_Z_LONG;
+ ch = *pszFmt++;
+ if (ch == 'l')
+ {
+ fFmtSize = RTSTR_Z_LONGLONG;
+ ch = *pszFmt++;
+ }
+ break;
+
+ case 'q': /* Used on BSD platforms. */
+ case 'L':
+ fFmtSize = RTSTR_Z_LONGLONG;
+ ch = *pszFmt++;
+ break;
+
+ case 'h':
+ fFmtSize = RTSTR_Z_HALF;
+ ch = *pszFmt++;
+ if (ch == 'h')
+ {
+ fFmtSize = RTSTR_Z_HALFHALF;
+ ch = *pszFmt++;
+ }
+ break;
+
+ case 'I': /* Used by Win32/64 compilers. */
+ if ( pszFmt[0] == '6'
+ && pszFmt[1] == '4')
+ {
+ pszFmt += 2;
+ fFmtSize = RTSTR_Z_MS_I64;
+ }
+ else if ( pszFmt[0] == '3'
+ && pszFmt[1] == '2')
+ {
+ pszFmt += 2;
+ fFmtSize = RTSTR_Z_MS_I32;
+ }
+ else
+ {
+ VFmtChkErrFmt(pState, pszFmt, "Unknow format type/size/flag 'I%c'", pszFmt[0]);
+ fFmtSize = RTSTR_Z_INTMAX;
+ }
+ ch = *pszFmt++;
+ break;
+ }
+
+ /*
+ * The type.
+ */
+ switch (ch)
+ {
+ /*
+ * Nested extensions.
+ */
+ case 'M': /* replace the format string (not stacked yet). */
+ {
+ if (*pszFmt)
+ VFmtChkErrFmt(pState, pszFmt, "Characters following '%%M' will be ignored");
+ if (fFmtSize != RTSTR_Z_DEFAULT)
+ VFmtChkWarnFmt(pState, pszFmt, "'%%M' does not support any size flags (%#x)", fFmtSize);
+ if (fFmtFlags != 0)
+ VFmtChkWarnFmt(pState, pszFmt, "'%%M' does not support any format flags (%#x)", fFmtFlags);
+ if (VFmtChkRequireStringArg(pState, pszPct, iArg, "'%M' expects a format string"))
+ VFmtChkHandleReplacementFormatString(pState, pszPct, iArg);
+ return;
+ }
+
+ case 'N': /* real nesting. */
+ {
+ if (fFmtSize != RTSTR_Z_DEFAULT)
+ VFmtChkWarnFmt(pState, pszFmt, "'%%N' does not support any size flags (%#x)", fFmtSize);
+ if (fFmtFlags != 0)
+ VFmtChkWarnFmt(pState, pszFmt, "'%%N' does not support any format flags (%#x)", fFmtFlags);
+ VFmtChkRequireStringArg(pState, pszPct, iArg, "'%N' expects a string followed by a va_list pointer");
+ VFmtChkRequireVaListPtrArg(pState, pszPct, iArg + 1, "'%N' expects a string followed by a va_list pointer");
+ iArg += 2;
+ break;
+ }
+
+ case 'R':
+ if ( pszFmt[0] == 'h'
+ && pszFmt[1] == 'X')
+ {
+ VFmtChkRequirePresentArg(pState, pszPct, iArg, "Expected argument");
+ iArg++;
+ }
+ RT_FALL_THROUGH();
+
+ default:
+ VFmtChkRequirePresentArg(pState, pszPct, iArg, "Expected argument");
+ iArg++;
+ break;
+ }
+ }
+}
+