VirtualBox

Changeset 56977 in vbox for trunk


Ignore:
Timestamp:
Jul 18, 2015 5:43:19 PM (9 years ago)
Author:
vboxsync
Message:

gccplugin: restructured the code a little, should be able to detect missing arguments now.

Location:
trunk/src/bldprogs
Files:
2 added
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/bldprogs/Makefile.kmk

    r56920 r56977  
    7272
    7373# temp hack.
    74 gccplugin.o gccplugin: gccplugin$(SUFF_DLL)
    75 gccplugin$(SUFF_DLL): gccplugin.cpp
    76         g++ -shared -fPIC -g -I$(shell gcc -print-file-name=plugin/include) -I$(PATH_ROOT)/include -DIN_RING3 -o $@ $<
     74VBoxCompilerPlugInsGcc.o VBoxCompilerPlugInsCommon.o VBoxCompilerPlugIns.o gccplugin: gccplugin$(SUFF_DLL)
     75gccplugin$(SUFF_DLL): VBoxCompilerPlugInsGcc.cpp VBoxCompilerPlugInsCommon.cpp VBoxCompilerPlugIns.h
     76        g++ -shared -fPIC -g \
     77                -DIN_RING3 \
     78                $(if-expr "$(KBUILD_TYPE)" != "release",-DDEBUG,) \
     79                -I$(shell gcc -print-file-name=plugin/include) \
     80                -I$(PATH_ROOT)/include \
     81                -o $@ \
     82                VBoxCompilerPlugInsGcc.cpp \
     83                VBoxCompilerPlugInsCommon.cpp
    7784
    7885
  • trunk/src/bldprogs/VBoxCompilerPlugInsGcc.cpp

    r56976 r56977  
    2222#include <iprt/cdefs.h>
    2323#include <iprt/stdarg.h>
    24 #include <iprt/string.h>
    2524
    2625#include "plugin.h"
     
    3130#include "cp/cp-tree.h"
    3231
     32#include "VBoxCompilerPlugIns.h"
     33
    3334
    3435/*********************************************************************************************************************************
     
    4243*   Defined Constants And Macros                                                                                                 *
    4344*********************************************************************************************************************************/
    44 #define GCCPLUGIN_DEBUG
    45 /** Debug printf. */
    46 #ifdef GCCPLUGIN_DEBUG
    47 # define dprintf(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
    48 #else
    49 # define dprintf(...) do { } while (0)
    50 #endif
    51 
    5245/** Convencience macro not present in earlier gcc versions. */
    5346#ifndef VAR_P
     
    6154#define MY_LOC(a_hPreferred, a_pState) EXPR_LOC_OR_LOC(a_hPreferred, (a_pState)->hFmtLoc)
    6255
    63 #define MY_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
    64 
    65 
    66 /*******************************************************************************
    67 *   Structures and Typedefs                                                    *
    68 *******************************************************************************/
    69 /** Checker state. */
    70 typedef struct MYCHECKSTATE
    71 {
    72     gimple      hStmt;
    73     long        iFmt;
    74     long        iArgs;
    75     location_t  hFmtLoc;
    76     const char *pszFmt;
    77 } MYCHECKSTATE;
    78 /** Pointer to my checker state. */
    79 typedef MYCHECKSTATE *PMYCHECKSTATE;
    8056
    8157
     
    147123
    148124
    149 #ifdef GCCPLUGIN_DEBUG
     125#ifdef DEBUG
    150126
    151127/**
     
    195171}
    196172
    197 #endif /* GCCPLUGIN_DEBUG */
    198 
    199 
    200 /**
    201  * Gate callback for my pass that indicates whether it should execute or not.
    202  * @returns true to execute.
    203  */
    204 static bool             MyPassGateCallback(void)
    205 {
    206     dprintf("MyPassGateCallback:\n");
    207     return true;
    208 }
    209 
    210 
    211 #define MYSTATE_FMT_FILE(a_pState)      LOCATION_FILE((a_pState)->hFmtLoc)
    212 #define MYSTATE_FMT_LINE(a_pState)      LOCATION_LINE((a_pState)->hFmtLoc)
    213 #define MYSTATE_FMT_COLUMN(a_pState)    LOCATION_COLUMN((a_pState)->hFmtLoc)
    214 
    215 void MyCheckWarnFmt(PMYCHECKSTATE pState, const char *pszLoc, const char *pszFormat, ...)
    216 {
    217     char szTmp[1024];
    218     va_list va;
    219     va_start(va, pszFormat);
    220     vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
    221     va_end(va);
    222 
    223 
    224     /* Create a location for pszLoc. */
    225     location_t hLoc      = pState->hFmtLoc;
     173#endif /* DEBUG */
     174
     175
     176static location_t MyGetLocationPlusColumnOffset(location_t hLoc, unsigned int offColumn)
     177{
     178    /*
     179     * Skip NOOPs, reserved locations and macro expansion.
     180     */
     181    if (   offColumn != 0
     182        && hLoc >= RESERVED_LOCATION_COUNT
     183        && !linemap_location_from_macro_expansion_p(line_table, hLoc))
     184    {
    226185#if __GNUC__ >= 5 /** @todo figure this... */
     186        /*
     187         * There is an API for doing this, nice.
     188         */
     189        location_t hNewLoc = linemap_position_for_loc_and_offset(line_table, hLoc, offColumn);
     190        if (hNewLoc && hNewLoc != hLoc)
     191        {
     192            dprintf("MyGetLocationPlusColumnOffset: hNewLoc=%#x hLoc=%#x offColumn=%u\n", hNewLoc, hLoc, offColumn);
     193            return hNewLoc;
     194        }
     195
     196#else
     197        /*
     198         * Have to do the job ourselves, it seems.  This is a bit hairy...
     199         */
     200        line_map const *pMap = NULL;
     201        location_t hLoc2 = linemap_resolve_location(line_table, hLoc, LRK_SPELLING_LOCATION, &pMap);
     202        if (hLoc2)
     203            hLoc = hLoc2;
     204
     205        /* Guard against wrap arounds and overlaps. */
     206        if (   hLoc + offColumn > MAP_START_LOCATION(pMap) /** @todo Use MAX_SOURCE_LOCATION? */
     207            && (   pMap == LINEMAPS_LAST_ORDINARY_MAP(line_table)
     208                || hLoc + offColumn < MAP_START_LOCATION((pMap + 1))))
     209        {
     210            /* Calc new column and check that it's within the valid range. */
     211            unsigned int uColumn = SOURCE_COLUMN(pMap, hLoc) + offColumn;
     212            if (uColumn < RT_BIT_32(ORDINARY_MAP_NUMBER_OF_COLUMN_BITS(pMap)))
     213            {
     214                /* Try add the position.  If we get a valid result, replace the location. */
     215                source_location hNewLoc = linemap_position_for_line_and_column((line_map *)pMap, SOURCE_LINE(pMap, hLoc), uColumn);
     216                if (   hNewLoc <= line_table->highest_location
     217                    && linemap_lookup(line_table, hNewLoc) != NULL)
     218                {
     219                    dprintf("MyGetLocationPlusColumnOffset: hNewLoc=%#x hLoc=%#x offColumn=%u uColumn=%u\n",
     220                            hNewLoc, hLoc, offColumn, uColumn);
     221                    return hNewLoc;
     222                }
     223            }
     224        }
     225#endif
     226    }
     227    dprintf("MyGetLocationPlusColumnOffset: taking fallback\n");
     228    return hLoc;
     229}
     230
     231
     232static location_t MyGetFormatStringLocation(PVFMTCHKSTATE pState, const char *pszLoc)
     233{
     234    location_t hLoc = pState->hFmtLoc;
    227235    intptr_t   offString = pszLoc - pState->pszFmt;
    228     if (   offString > 0
     236    if (   offString >= 0
    229237        && !linemap_location_from_macro_expansion_p(line_table, hLoc))
    230238    {
    231239        unsigned            uCol    = 1 + offString;
    232240        expanded_location   XLoc    = expand_location_to_spelling_point(hLoc);
    233         int                 cchLine;
    234 # if __GNUC__ >= 5 /** @todo figure this... */
     241        int                 cchLine = 0;
     242#if __GNUC__ >= 5 /** @todo figure this... */
    235243        const char         *pszLine = location_get_source_line(XLoc, &cchLine);
    236 # else
     244#else
    237245        const char         *pszLine = location_get_source_line(XLoc);
    238         int                 cchLine = 0;
    239246        if (pszLine)
    240247        {
     
    244251            cchLine = (int)(pszEol - pszLine);
    245252        }
    246 # endif
     253#endif
    247254        if (pszLine)
    248255        {
     
    251258            cchLine -= XLoc.column - 1;
    252259        }
    253         location_t hNewLoc = linemap_position_for_loc_and_offset(line_table, hLoc, 0);
    254         if (hNewLoc)
    255             hLoc = hNewLoc;
    256     }
    257 #endif
    258 
    259     /* display the warning. */
    260     warning_at(hLoc, 0, "%s", szTmp);
    261 }
    262 
    263 
    264 
    265 /**
    266  * Checks that @a iFmtArg isn't present or a valid final dummy argument.
    267  *
    268  * Will issue warning/error if there are more arguments at @a iFmtArg.
    269  *
    270  * @param   pState              The format string checking state.
    271  * @param   iArg                The index of the end of arguments, this is
    272  *                              relative to MYCHECKSTATE::iArgs.
    273  */
    274 void MyCheckFinalArg(PMYCHECKSTATE pState, unsigned iArg)
    275 {
    276     dprintf("MyCheckFinalArg: iArg=%u iArgs=%ld cArgs=%u\n", iArg, pState->iArgs, gimple_call_num_args(pState->hStmt));
    277     if (pState->iArgs > 0)
    278     {
    279         iArg += pState->iArgs - 1;
    280         unsigned cArgs = gimple_call_num_args(pState->hStmt);
    281         if (iArg == cArgs)
    282         { /* fine */ }
    283         else if (iArg < cArgs)
    284         {
    285             tree hArg = gimple_call_arg(pState->hStmt, iArg);
    286             if (cArgs - iArg > 1)
    287                 warning_at(MY_LOC(hArg, pState), 0, "%u extra arguments not consumed by format string", cArgs - iArg);
    288             else if (   TREE_CODE(hArg) != INTEGER_CST
    289                      || !TREE_INT_CST(hArg).fits_shwi()
    290                      || TREE_INT_CST(hArg).to_shwi() != -99) /* ignore final dummy argument: ..., -99); */
    291                 warning_at(MY_LOC(hArg, pState), 0, "one extra argument not consumed by format string");
    292         }
    293         /* This should be handled elsewhere, but just in case. */
    294         else if (iArg - 1 == cArgs)
    295             warning_at(pState->hFmtLoc, 0, "one argument too few");
    296         else
    297             warning_at(pState->hFmtLoc, 0, "%u arguments too few", iArg - cArgs);
    298     }
    299 }
    300 
    301 void MyCheckIntArg(PMYCHECKSTATE pState, const char *pszFmt, unsigned iArg, const char *pszMessage)
    302 {
    303 
    304 }
    305 
    306 
    307 
    308 /**
    309  * Does the actual format string checking.
    310  *
    311  * @todo    Move this to different file common to both GCC and CLANG later.
    312  *
    313  * @param   pState              The format string checking state.
    314  * @param   pszFmt              The format string.
    315  */
    316 void MyCheckFormatCString(PMYCHECKSTATE pState, const char *pszFmt)
    317 {
    318     dprintf("checker2: \"%s\" at %s:%d col %d\n", pszFmt,
    319             MYSTATE_FMT_FILE(pState), MYSTATE_FMT_LINE(pState), MYSTATE_FMT_COLUMN(pState));
    320     pState->pszFmt = pszFmt;
    321 
    322     unsigned iArg = 0;
    323     for (;;)
    324     {
    325         /*
    326          * Skip to the next argument.
    327          * Quits the loop with the first char following the '%' in 'ch'.
    328          */
    329         char ch;
    330         for (;;)
    331         {
    332             ch = *pszFmt++;
    333             if (ch == '%')
    334             {
    335                 ch = *pszFmt++;
    336                 if (ch != '%')
    337                     break;
    338             }
    339             else if (ch == '\0')
    340             {
    341                 MyCheckFinalArg(pState, iArg);
    342                 return;
    343             }
    344         }
    345 
    346         /*
    347          * Flags
    348          */
    349         uint32_t fFlags = 0;
    350         for (;;)
    351         {
    352             uint32_t fFlag;
    353             switch (ch)
    354             {
    355                 case '#':   fFlag = RTSTR_F_SPECIAL;      break;
    356                 case '-':   fFlag = RTSTR_F_LEFT;         break;
    357                 case '+':   fFlag = RTSTR_F_PLUS;         break;
    358                 case ' ':   fFlag = RTSTR_F_BLANK;        break;
    359                 case '0':   fFlag = RTSTR_F_ZEROPAD;      break;
    360                 case '\'':  fFlag = RTSTR_F_THOUSAND_SEP; break;
    361                 default:    fFlag = 0;                    break;
    362             }
    363             if (!fFlag)
    364                 break;
    365             if (fFlags & fFlag)
    366                 MyCheckWarnFmt(pState, pszFmt - 1, "duplicate flag '%c'", ch);
    367             fFlags |= fFlag;
    368             ch = *pszFmt++;
    369         }
    370 
    371         /*
    372          * Width.
    373          */
    374         int cchWidth = -1;
    375         if (MY_ISDIGIT(ch))
    376         {
    377             cchWidth = ch - '0';
    378             while (   (ch = *pszFmt++) != '\0'
    379                    && MY_ISDIGIT(ch))
    380             {
    381                 cchWidth *= 10;
    382                 cchWidth += ch - '0';
    383             }
    384             fFlags |= RTSTR_F_WIDTH;
    385         }
    386         else if (ch == '*')
    387         {
    388             MyCheckIntArg(pState, pszFmt - 1, iArg, "width should be an 'int' sized argument");
    389             iArg++;
    390             cchWidth = 0;
    391             fFlags |= RTSTR_F_WIDTH;
    392         }
    393 
    394         /*
    395          * Precision
    396          */
    397         int cchPrecision = -1;
    398         if (ch == '.')
    399         {
    400             ch = *pszFmt++;
    401             if (MY_ISDIGIT(ch))
    402             {
    403                 cchPrecision = ch - '0';
    404                 while (   (ch = *pszFmt++) != '\0'
    405                        && MY_ISDIGIT(ch))
    406                 {
    407                     cchPrecision *= 10;
    408                     cchPrecision += ch - '0';
    409                 }
    410             }
    411             else if (ch == '*')
    412             {
    413                 MyCheckIntArg(pState, pszFmt - 1, iArg, "precision should be an 'int' sized argument");
    414                 iArg++;
    415                 cchWidth = 0;
    416             }
    417             else
    418                 MyCheckWarnFmt(pState, pszFmt - 1, "Missing precision value, only got the '.'");
    419             if (cchPrecision < 0)
    420             {
    421                 MyCheckWarnFmt(pState, pszFmt - 1, "Negative precision value: %d", cchPrecision);
    422                 cchPrecision = 0;
    423             }
    424             fFlags |= RTSTR_F_PRECISION;
    425         }
    426 
    427         /*
    428          * Argument size.
    429          */
    430         char chArgSize = ch;
    431         switch (ch)
    432         {
    433             default:
    434                 chArgSize = '\0';
    435                 break;
    436 
    437             case 'z':
    438             case 'L':
    439             case 'j':
    440             case 't':
    441                 ch = *pszFmt++;
    442                 break;
    443 
    444             case 'l':
    445                 ch = *pszFmt++;
    446                 if (ch == 'l')
    447                 {
    448                     chArgSize = 'L';
    449                     ch = *pszFmt++;
    450                 }
    451                 break;
    452 
    453             case 'h':
    454                 ch = *pszFmt++;
    455                 if (ch == 'h')
    456                 {
    457                     chArgSize = 'H';
    458                     ch = *pszFmt++;
    459                 }
    460                 break;
    461 
    462             case 'I': /* Used by Win32/64 compilers. */
    463                 if (   pszFmt[0] == '6'
    464                     && pszFmt[1] == '4')
    465                 {
    466                     pszFmt += 2;
    467                     chArgSize = 'L';
    468                 }
    469                 else if (   pszFmt[0] == '3'
    470                          && pszFmt[1] == '2')
    471                 {
    472                     pszFmt += 2;
    473                     chArgSize = 0;
    474                 }
    475                 else
    476                     chArgSize = 'j';
    477                 ch = *pszFmt++;
    478                 break;
    479 
    480             case 'q': /* Used on BSD platforms. */
    481                 chArgSize = 'L';
    482                 ch = *pszFmt++;
    483                 break;
    484         }
    485 
    486         /*
    487          * The type.
    488          */
    489 
    490     }
     260
     261        hLoc = MyGetLocationPlusColumnOffset(hLoc, uCol);
     262    }
     263    return hLoc;
    491264}
    492265
     
    501274 * @param   hFmtArg             The format string node.
    502275 */
    503 DECL_NO_INLINE(static, void) MyCheckFormatNonRecursive(PMYCHECKSTATE pState, tree hFmtArg)
     276DECL_NO_INLINE(static, void) MyCheckFormatNonRecursive(PVFMTCHKSTATE pState, tree hFmtArg)
    504277{
    505278    dprintf("checker: hFmtArg=%p %s\n", hFmtArg, tree_code_name[TREE_CODE(hFmtArg)]);
     
    636409 * @param   hFmtArg             The format string node.
    637410 */
    638 static void MyCheckFormatRecursive(PMYCHECKSTATE pState, tree hFmtArg)
     411static void MyCheckFormatRecursive(PVFMTCHKSTATE pState, tree hFmtArg)
    639412{
    640413    /*
     
    689462            gimple const            hStmt   = gsi_stmt(hStmtItr);
    690463            enum gimple_code const  enmCode = gimple_code(hStmt);
    691 #ifdef GCCPLUGIN_DEBUG
     464#ifdef DEBUG
    692465            unsigned const          cOps    = gimple_num_ops(hStmt);
    693466            dprintf("   hStmt=%p %s (%d) ops=%d\n", hStmt, gimple_code_name[enmCode], enmCode, cOps);
     
    709482                tree const hFnType   = gimple_call_fntype(hStmt);
    710483                tree const hAttr     = lookup_attribute("iprt_format", TYPE_ATTRIBUTES(hFnType));
    711 #ifdef GCCPLUGIN_DEBUG
     484#ifdef DEBUG
    712485                tree const hFnDecl   = gimple_call_fndecl(hStmt);
    713486                dprintf("     hFn    =%p %s(%d); args=%d\n",
     
    725498                     */
    726499                    tree const hAttrArgs = TREE_VALUE(hAttr);
    727                     MYCHECKSTATE State;
     500                    VFMTCHKSTATE State;
    728501                    State.iFmt    = TREE_INT_CST(TREE_VALUE(hAttrArgs)).to_shwi();
    729502                    State.iArgs   = TREE_INT_CST(TREE_VALUE(TREE_CHAIN(hAttrArgs))).to_shwi();
     
    743516
    744517
     518/**
     519 * Gate callback for my pass that indicates whether it should execute or not.
     520 * @returns true to execute.
     521 */
     522static bool             MyPassGateCallback(void)
     523{
     524    dprintf("MyPassGateCallback:\n");
     525    return true;
     526}
     527
    745528
    746529/**
     
    810593}
    811594
     595
     596
     597
     598/*
     599 *
     600 * Functions used by the common code.
     601 * Functions used by the common code.
     602 * Functions used by the common code.
     603 *
     604 */
     605
     606void VFmtChkWarnFmt(PVFMTCHKSTATE pState, const char *pszLoc, const char *pszFormat, ...)
     607{
     608    char szTmp[1024];
     609    va_list va;
     610    va_start(va, pszFormat);
     611    vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
     612    va_end(va);
     613
     614    /* display the warning. */
     615    warning_at(MyGetFormatStringLocation(pState, pszLoc), 0, "%s", szTmp);
     616}
     617
     618
     619
     620void VFmtChkVerifyEndOfArgs(PVFMTCHKSTATE pState, unsigned iArg)
     621{
     622    dprintf("VFmtChkVerifyFinalArg: iArg=%u iArgs=%ld cArgs=%u\n", iArg, pState->iArgs, gimple_call_num_args(pState->hStmt));
     623    if (pState->iArgs > 0)
     624    {
     625        iArg += pState->iArgs - 1;
     626        unsigned cArgs = gimple_call_num_args(pState->hStmt);
     627        if (iArg == cArgs)
     628        { /* fine */ }
     629        else if (iArg < cArgs)
     630        {
     631            tree hArg = gimple_call_arg(pState->hStmt, iArg);
     632            if (cArgs - iArg > 1)
     633                warning_at(MY_LOC(hArg, pState), 0, "%u extra arguments not consumed by format string", cArgs - iArg);
     634            else if (   TREE_CODE(hArg) != INTEGER_CST
     635                     || !TREE_INT_CST(hArg).fits_shwi()
     636                     || TREE_INT_CST(hArg).to_shwi() != -99) /* ignore final dummy argument: ..., -99); */
     637                warning_at(MY_LOC(hArg, pState), 0, "one extra argument not consumed by format string");
     638        }
     639        /* This should be handled elsewhere, but just in case. */
     640        else if (iArg - 1 == cArgs)
     641            warning_at(pState->hFmtLoc, 0, "one argument too few");
     642        else
     643            warning_at(pState->hFmtLoc, 0, "%u arguments too few", iArg - cArgs);
     644    }
     645}
     646
     647
     648bool VFmtChkRequirePresentArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
     649{
     650    if (pState->iArgs > 0)
     651    {
     652        iArg += pState->iArgs - 1;
     653        unsigned cArgs = gimple_call_num_args(pState->hStmt);
     654        if (iArg >= cArgs)
     655        {
     656            VFmtChkWarnFmt(pState, pszLoc, "Missing argument! %s", pszMessage);
     657            return false;
     658        }
     659    }
     660    return true;
     661}
     662
     663
     664bool VFmtChkRequireIntArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
     665{
     666    if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
     667    {
     668        /** @todo type check.  */
     669        return true;
     670    }
     671    return false;
     672}
     673
     674
     675bool VFmtChkRequireStringArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
     676{
     677    if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
     678    {
     679        /** @todo type check.  */
     680        return true;
     681    }
     682    return false;
     683}
     684
     685
     686bool VFmtChkRequireVaListPtrArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
     687{
     688    if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
     689    {
     690        /** @todo type check.  */
     691        return true;
     692    }
     693    return false;
     694}
     695
     696
     697
     698void VFmtChkHandleReplacementFormatString(PVFMTCHKSTATE pState, const char *pszPctM, unsigned iArg)
     699{
     700    if (pState->iArgs > 0)
     701    {
     702        pState->iArgs += iArg;
     703
     704    }
     705}
     706
     707
     708const char  *VFmtChkGetFmtLocFile(PVFMTCHKSTATE pState)
     709{
     710    return LOCATION_FILE(pState->hFmtLoc);
     711}
     712
     713
     714unsigned int VFmtChkGetFmtLocLine(PVFMTCHKSTATE pState)
     715{
     716    return LOCATION_LINE(pState->hFmtLoc);
     717}
     718
     719
     720unsigned int VFmtChkGetFmtLocColumn(PVFMTCHKSTATE pState)
     721{
     722    return LOCATION_COLUMN(pState->hFmtLoc);
     723}
     724
Note: See TracChangeset for help on using the changeset viewer.

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