iid_iunknown created this revision.
iid_iunknown added a project: clang.

This is a patch for PR33484.
The clang's typo correction logic may fall into an infinite loop when reaching 
the typo correction limit.

When some complex expression has multiple typos in it, clang finds possible 
corrections for each typo and processes various permutations of these 
corrections. The typo corrections counter is incremented during the process and 
compared to the max allowed limit (50 by default). Hang may happen if the limit 
is reached in the middle of complex expression processing. In this case 
transform of the current part of the expression fails, making clang ignore its 
subsequent parts and bail out to the main transform loop in 
`TransformTypos::Transform(Expr *E)`. On the next iteration, clang fails at the 
very beginning of transform and no longer reaches the rest of the expression 
immediately bailing out to the main loop. The transform cannot advance since 
this moment. As the loop exit condition requires either a fully successful 
transform or having all the permutations processed, it can never become true.

Yet another reproducer with a readable C++ code:

  namespace
  {
    struct V
    {
      float x;
    };
  
    class H
    {
    public:
      const V& getV() const { return mV; }
      int getN() const { return mN; }
    private:
      V mV;
      int mN;
    };
  
    class T
    {
    public:
      const H& getH0() const { return mH0; }
      const H& getH1() const { return mH1; }
  
      const V& getV0() const { return mH0.getV(); }
      const V& getV1() const { return mH1.getV(); }
  
    private:
      H mH0;
      H mH1;
    };
        
    T sT;
    H sH;
  }
  
  void func()
  {
    ( sT.getH2().getM() > sH.getM() ?
      sT.getH3() :
      0 );
  }

Here, both the condition and LHS of `?:` have typos. If the limit is exceeded, 
the transform will fail on the condition and will no longer proceed to LHS and 
process its substitutions.

The patch adds a limit check into the main loop exit condition.


Repository:
  rL LLVM

https://reviews.llvm.org/D34430

Files:
  lib/Sema/SemaExprCXX.cpp


Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7246,10 +7246,13 @@
   /// TransformCache). Returns true if there is still any untried combinations
   /// of corrections.
   bool CheckAndAdvanceTypoExprCorrectionStreams() {
+       bool CheckLimitExceeded =
+        SemaRef.TyposCorrected >=
+        SemaRef.getDiagnostics().getDiagnosticOptions().SpellCheckingLimit;
     for (auto TE : TypoExprs) {
       auto &State = SemaRef.getTypoExprState(TE);
       TransformCache.erase(TE);
-      if (!State.Consumer->finished())
+         if (!CheckLimitExceeded && !State.Consumer->finished())
         return true;
       State.Consumer->resetCorrectionStream();
     }


Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7246,10 +7246,13 @@
   /// TransformCache). Returns true if there is still any untried combinations
   /// of corrections.
   bool CheckAndAdvanceTypoExprCorrectionStreams() {
+	bool CheckLimitExceeded =
+        SemaRef.TyposCorrected >=
+        SemaRef.getDiagnostics().getDiagnosticOptions().SpellCheckingLimit;
     for (auto TE : TypoExprs) {
       auto &State = SemaRef.getTypoExprState(TE);
       TransformCache.erase(TE);
-      if (!State.Consumer->finished())
+	  if (!CheckLimitExceeded && !State.Consumer->finished())
         return true;
       State.Consumer->resetCorrectionStream();
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to