tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ValidateSwitch.cpp (9508B)


      1 //
      2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 #include "compiler/translator/ValidateSwitch.h"
      8 
      9 #include "compiler/translator/Diagnostics.h"
     10 #include "compiler/translator/tree_util/IntermTraverse.h"
     11 
     12 namespace sh
     13 {
     14 
     15 namespace
     16 {
     17 
     18 const int kMaxAllowedTraversalDepth = 256;
     19 
     20 class ValidateSwitch : public TIntermTraverser
     21 {
     22  public:
     23    static bool validate(TBasicType switchType,
     24                         TDiagnostics *diagnostics,
     25                         TIntermBlock *statementList,
     26                         const TSourceLoc &loc);
     27 
     28    void visitSymbol(TIntermSymbol *) override;
     29    void visitConstantUnion(TIntermConstantUnion *) override;
     30    bool visitDeclaration(Visit, TIntermDeclaration *) override;
     31    bool visitBlock(Visit visit, TIntermBlock *) override;
     32    bool visitBinary(Visit, TIntermBinary *) override;
     33    bool visitUnary(Visit, TIntermUnary *) override;
     34    bool visitTernary(Visit, TIntermTernary *) override;
     35    bool visitSwizzle(Visit, TIntermSwizzle *) override;
     36    bool visitIfElse(Visit visit, TIntermIfElse *) override;
     37    bool visitSwitch(Visit, TIntermSwitch *) override;
     38    bool visitCase(Visit, TIntermCase *node) override;
     39    bool visitAggregate(Visit, TIntermAggregate *) override;
     40    bool visitLoop(Visit visit, TIntermLoop *) override;
     41    bool visitBranch(Visit, TIntermBranch *) override;
     42 
     43  private:
     44    ValidateSwitch(TBasicType switchType, TDiagnostics *context);
     45 
     46    bool validateInternal(const TSourceLoc &loc);
     47 
     48    TBasicType mSwitchType;
     49    TDiagnostics *mDiagnostics;
     50    bool mCaseTypeMismatch;
     51    bool mFirstCaseFound;
     52    bool mStatementBeforeCase;
     53    bool mLastStatementWasCase;
     54    int mControlFlowDepth;
     55    bool mCaseInsideControlFlow;
     56    int mDefaultCount;
     57    std::set<int> mCasesSigned;
     58    std::set<unsigned int> mCasesUnsigned;
     59    bool mDuplicateCases;
     60 };
     61 
     62 bool ValidateSwitch::validate(TBasicType switchType,
     63                              TDiagnostics *diagnostics,
     64                              TIntermBlock *statementList,
     65                              const TSourceLoc &loc)
     66 {
     67    ValidateSwitch validate(switchType, diagnostics);
     68    ASSERT(statementList);
     69    statementList->traverse(&validate);
     70    return validate.validateInternal(loc);
     71 }
     72 
     73 ValidateSwitch::ValidateSwitch(TBasicType switchType, TDiagnostics *diagnostics)
     74    : TIntermTraverser(true, false, true, nullptr),
     75      mSwitchType(switchType),
     76      mDiagnostics(diagnostics),
     77      mCaseTypeMismatch(false),
     78      mFirstCaseFound(false),
     79      mStatementBeforeCase(false),
     80      mLastStatementWasCase(false),
     81      mControlFlowDepth(0),
     82      mCaseInsideControlFlow(false),
     83      mDefaultCount(0),
     84      mDuplicateCases(false)
     85 {
     86    setMaxAllowedDepth(kMaxAllowedTraversalDepth);
     87 }
     88 
     89 void ValidateSwitch::visitSymbol(TIntermSymbol *)
     90 {
     91    if (!mFirstCaseFound)
     92        mStatementBeforeCase = true;
     93    mLastStatementWasCase = false;
     94 }
     95 
     96 void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *)
     97 {
     98    // Conditions of case labels are not traversed, so this is some other constant
     99    // Could be just a statement like "0;"
    100    if (!mFirstCaseFound)
    101        mStatementBeforeCase = true;
    102    mLastStatementWasCase = false;
    103 }
    104 
    105 bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *)
    106 {
    107    if (!mFirstCaseFound)
    108        mStatementBeforeCase = true;
    109    mLastStatementWasCase = false;
    110    return true;
    111 }
    112 
    113 bool ValidateSwitch::visitBlock(Visit visit, TIntermBlock *)
    114 {
    115    if (getParentNode() != nullptr)
    116    {
    117        if (!mFirstCaseFound)
    118            mStatementBeforeCase = true;
    119        mLastStatementWasCase = false;
    120        if (visit == PreVisit)
    121            ++mControlFlowDepth;
    122        if (visit == PostVisit)
    123            --mControlFlowDepth;
    124    }
    125    return true;
    126 }
    127 
    128 bool ValidateSwitch::visitBinary(Visit, TIntermBinary *)
    129 {
    130    if (!mFirstCaseFound)
    131        mStatementBeforeCase = true;
    132    mLastStatementWasCase = false;
    133    return true;
    134 }
    135 
    136 bool ValidateSwitch::visitUnary(Visit, TIntermUnary *)
    137 {
    138    if (!mFirstCaseFound)
    139        mStatementBeforeCase = true;
    140    mLastStatementWasCase = false;
    141    return true;
    142 }
    143 
    144 bool ValidateSwitch::visitTernary(Visit, TIntermTernary *)
    145 {
    146    if (!mFirstCaseFound)
    147        mStatementBeforeCase = true;
    148    mLastStatementWasCase = false;
    149    return true;
    150 }
    151 
    152 bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *)
    153 {
    154    if (!mFirstCaseFound)
    155        mStatementBeforeCase = true;
    156    mLastStatementWasCase = false;
    157    return true;
    158 }
    159 
    160 bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *)
    161 {
    162    if (visit == PreVisit)
    163        ++mControlFlowDepth;
    164    if (visit == PostVisit)
    165        --mControlFlowDepth;
    166    if (!mFirstCaseFound)
    167        mStatementBeforeCase = true;
    168    mLastStatementWasCase = false;
    169    return true;
    170 }
    171 
    172 bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *)
    173 {
    174    if (!mFirstCaseFound)
    175        mStatementBeforeCase = true;
    176    mLastStatementWasCase = false;
    177    // Don't go into nested switch statements
    178    return false;
    179 }
    180 
    181 bool ValidateSwitch::visitCase(Visit, TIntermCase *node)
    182 {
    183    const char *nodeStr = node->hasCondition() ? "case" : "default";
    184    if (mControlFlowDepth > 0)
    185    {
    186        mDiagnostics->error(node->getLine(), "label statement nested inside control flow", nodeStr);
    187        mCaseInsideControlFlow = true;
    188    }
    189    mFirstCaseFound       = true;
    190    mLastStatementWasCase = true;
    191    if (!node->hasCondition())
    192    {
    193        ++mDefaultCount;
    194        if (mDefaultCount > 1)
    195        {
    196            mDiagnostics->error(node->getLine(), "duplicate default label", nodeStr);
    197        }
    198    }
    199    else
    200    {
    201        TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion();
    202        if (condition == nullptr)
    203        {
    204            // This can happen in error cases.
    205            return false;
    206        }
    207        TBasicType conditionType = condition->getBasicType();
    208        if (conditionType != mSwitchType)
    209        {
    210            mDiagnostics->error(condition->getLine(),
    211                                "case label type does not match switch init-expression type",
    212                                nodeStr);
    213            mCaseTypeMismatch = true;
    214        }
    215 
    216        if (conditionType == EbtInt)
    217        {
    218            int iConst = condition->getIConst(0);
    219            if (mCasesSigned.find(iConst) != mCasesSigned.end())
    220            {
    221                mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr);
    222                mDuplicateCases = true;
    223            }
    224            else
    225            {
    226                mCasesSigned.insert(iConst);
    227            }
    228        }
    229        else if (conditionType == EbtUInt)
    230        {
    231            unsigned int uConst = condition->getUConst(0);
    232            if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end())
    233            {
    234                mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr);
    235                mDuplicateCases = true;
    236            }
    237            else
    238            {
    239                mCasesUnsigned.insert(uConst);
    240            }
    241        }
    242        // Other types are possible only in error cases, where the error has already been generated
    243        // when parsing the case statement.
    244    }
    245    // Don't traverse the condition of the case statement
    246    return false;
    247 }
    248 
    249 bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *)
    250 {
    251    if (getParentNode() != nullptr)
    252    {
    253        // This is not the statementList node, but some other node.
    254        if (!mFirstCaseFound)
    255            mStatementBeforeCase = true;
    256        mLastStatementWasCase = false;
    257    }
    258    return true;
    259 }
    260 
    261 bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *)
    262 {
    263    if (visit == PreVisit)
    264        ++mControlFlowDepth;
    265    if (visit == PostVisit)
    266        --mControlFlowDepth;
    267    if (!mFirstCaseFound)
    268        mStatementBeforeCase = true;
    269    mLastStatementWasCase = false;
    270    return true;
    271 }
    272 
    273 bool ValidateSwitch::visitBranch(Visit, TIntermBranch *)
    274 {
    275    if (!mFirstCaseFound)
    276        mStatementBeforeCase = true;
    277    mLastStatementWasCase = false;
    278    return true;
    279 }
    280 
    281 bool ValidateSwitch::validateInternal(const TSourceLoc &loc)
    282 {
    283    if (mStatementBeforeCase)
    284    {
    285        mDiagnostics->error(loc, "statement before the first label", "switch");
    286    }
    287    if (mLastStatementWasCase)
    288    {
    289        // There have been some differences between versions of GLSL ES specs on whether this should
    290        // be an error or not, but as of early 2018 the latest discussion is that this is an error
    291        // also on GLSL ES versions newer than 3.00.
    292        mDiagnostics->error(
    293            loc, "no statement between the last label and the end of the switch statement",
    294            "switch");
    295    }
    296    if (getMaxDepth() >= kMaxAllowedTraversalDepth)
    297    {
    298        mDiagnostics->error(loc, "too complex expressions inside a switch statement", "switch");
    299    }
    300    return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow &&
    301           !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases &&
    302           getMaxDepth() < kMaxAllowedTraversalDepth;
    303 }
    304 
    305 }  // anonymous namespace
    306 
    307 bool ValidateSwitchStatementList(TBasicType switchType,
    308                                 TDiagnostics *diagnostics,
    309                                 TIntermBlock *statementList,
    310                                 const TSourceLoc &loc)
    311 {
    312    return ValidateSwitch::validate(switchType, diagnostics, statementList, loc);
    313 }
    314 
    315 }  // namespace sh