Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang static analyzer] False negatives related to symbol values #108520

Open
tianxinghe opened this issue Sep 13, 2024 · 2 comments
Open

[clang static analyzer] False negatives related to symbol values #108520

tianxinghe opened this issue Sep 13, 2024 · 2 comments

Comments

@tianxinghe
Copy link

tianxinghe commented Sep 13, 2024

commit 3e47883 (HEAD -> main, origin/main, origin/HEAD)
Author: Giulio Eulisse 10544+ktf@users.noreply.github.com
Date: Thu Sep 5 10:16:51 2024 +0200

Recover performance loss after PagedVector introduction (#67972)

clang --analyze --analyzer-no-default-checks -Xanalyzer -analyzer-checker=core.NullDereference -Xanalyzer -analyzer-config -Xanalyzer -mode=deep -Xanalyzer -analyzer-output=text

For this 200-line test case, the static analyzer failed to detect the null pointer dereference bug.
It is important to note that removing any one of the following pieces of dead code allows the analyzer to work correctly.
v37 = (input2) >= (49);
v38 = (166841049) > (input1);
v10 = (input0) < (2067997187);
v11 = (input1) <= (618503425);

  /* Provide Declarations */
    #include <stdint.h>
    #include <stdio.h>
    #ifndef __cplusplus
    typedef unsigned char bool;
    #endif
    
    /* External Global Variable Declarations */
    
    /* Function Declarations */
    uint8_t* malloc(uint64_t);
    uint64_t atol(uint8_t*);
    void free(uint8_t*);
    int main(int, char **);
    void func0(uint8_t**, uint8_t**, uint8_t*, uint64_t, uint8_t);
    
    /* Global Variable Definitions and Initialization */
    uint64_t* args;
    uint32_t num_args = 3;
    
    /* Function Bodies */
    
    void init(uint32_t _1, uint8_t** argv) {
         args = (uint64_t*) malloc(num_args * sizeof(uint64_t));
         for (int i = 1; i <= 3; ++i) {
             args[i - 1] = atol(argv[i]);
         }
         
         uint8_t *p = (uint8_t*) malloc(4);
         free(p);
    }
    
    int main(int argc, char ** argv) {
      uint32_t ac = (uint32_t)argc;
      uint8_t** av = (uint8_t**)argv;
      uint64_t* v1;
      uint8_t v2;
      uint64_t* inptr;
      uint64_t input0;
      uint64_t* inptr1;
      uint64_t input1;
      uint64_t* inptr2;
      uint64_t input2;
      uint8_t v3;
      uint8_t v4;
      uint8_t* v5;
      uint8_t v6;
      uint8_t* v7;
      uint8_t v8;
      uint8_t v9;
      bool v10;
      bool v11;
      uint8_t v13;
      uint8_t v14;
      uint8_t* v15;
      uint8_t v16;
      uint8_t v17;
      bool v18;
      uint8_t v19;
      bool v20;
      uint64_t v21;
      bool v22;
      uint8_t v23;
      uint64_t v24;
      uint8_t* v25;
      uint8_t** v26;
      uint8_t** v27;
      uint8_t v28;
      uint8_t v29;
      uint8_t v30;
      bool v31;
      bool v32;
      uint64_t v33;
      bool v34;
      uint64_t v35;
      uint8_t v36;
      bool v37;
      bool v38;
      
      init(ac, av);
      v1 = args;
      inptr = (&(*v1));
      input0 = *inptr;
      inptr1 = (&v1[((int64_t)1)]);
      input1 = *inptr1;
      inptr2 = (&v1[((int64_t)2)]);
      input2 = *inptr2;
      v7 = (&v8);
      v37 = (input2) >= (49);
      v38 = (166841049) > (input1);
      v10 = (input0) < (2067997187);
      v11 = (input1) <= (618503425);
      v8 = 1;
      v7 = ((uint8_t*)/*NULL*/0); // null pointer
      v26 = ((uint8_t**)/*NULL*/0);
      v26 = (&v25);
      v27 = v26;
      v6 = 138u;
      func0((&v25), v27, (&v6), 1, 1); // aliases &v25 v27
      v28 = ((uint8_t)input2);
      v29 = (1 - v28);
      v4 = 137u;
      v31 = ((int64_t)input0) < ((int64_t)2900235183);
      v32 = input1 == input2;
      if (v32) {
        goto block1;
      } else {
        goto block2;
      }
    
    block4:
      *v5 = 1;
      func0((&v7), (&v5), (&v23), input1, 97u);
      goto exit;
    
    block3:
      if (input0 >= 351170948) {
        goto block4;
      } else {
        goto block5;
      }
    
    block5:
      v7 = (&v3);
      goto exit;
    
    block1:
      v22 = 1707955933 == input1;
      v5 = (&v23);
      v20 = ((int8_t)v29) > ((int8_t)13);
      goto block3;
    
    exit:
      v33 = *inptr;
      return 0;
      
    block2:
      v7 = (&v4);
      v34 = v29 == 101u;
      goto block1;
    }
    
    
    void func0(uint8_t** a1, uint8_t** a2, uint8_t* a3, uint64_t a4, uint8_t a5) {
      uint64_t v1;
      uint8_t v2;
      uint64_t v3;
      uint8_t v4;
      uint64_t v5;
      uint8_t v6;
      uint8_t* bugptr;
      uint8_t bug;
      uint64_t v7;
      uint64_t v8;
      uint8_t v9;
      bool v10;
      uint8_t v11;
      uint64_t v12;
      uint8_t v13;
      uint64_t v14;
      bool v15;
    
      v3 = 0;
      v4 = *a3;
      v5 = ((int64_t)(int8_t)v4);
      goto block1;
    
    block5:
      v2 = v4;
      bugptr = *a1;
      bug = *bugptr; // null dereference
      v6 = bug;
      goto exit;
    
    block4:
      v7 = v3;
      v8 = v7 ^ v12;
      v2 = v4;
      v9 = ((uint8_t)v8);
      v10 = ((int8_t)v4) < ((int8_t)v9);
      if (v10) {
        goto block6;
      } else {
        goto block5;
      }
      
    block6:
      v3 = 2;
      goto exit;
    
    block2:
      v11 = *a3;
      v12 = ((int64_t)(int8_t)v11);
      goto block4;
    
    block1:
      *a2 = (&v2);
      v13 = *a3;
      v14 = ((int64_t)(int8_t)v13);
      v15 = v5 <= v14;
      if (v15) {
        goto block2;
      } else {
        goto block3;
      }
    
    exit:
      return;
      
    block3:
      v3 = 1;
      goto block2;
    }
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Sep 13, 2024
@EugeneZelenko EugeneZelenko added clang:static analyzer false-negative and removed clang Clang issues not falling into any other category labels Sep 13, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 13, 2024

@llvm/issue-subscribers-clang-static-analyzer

Author: Tianxing He (tianxinghe)

commit 3e47883 (HEAD -> main, origin/main, origin/HEAD) Author: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu Sep 5 10:16:51 2024 +0200
Recover performance loss after PagedVector introduction (#<!-- -->67972)

clang --analyze --analyzer-no-default-checks -Xanalyzer -analyzer-checker=core.NullDereference -Xanalyzer -analyzer-config -Xanalyzer -mode=deep -Xanalyzer -analyzer-output=text

For this 200-line test case, the static analyzer failed to detect the null pointer dereference bug.
It is important to note that removing any one of the following pieces of dead code allows the analyzer to work correctly.
v37 = (input2) &gt;= (49);
v38 = (166841049) &gt; (input1);
v10 = (input0) &lt; (2067997187);
v11 = (input1) &lt;= (618503425);

  /* Provide Declarations */
    #include &lt;stdint.h&gt;
    #include &lt;stdio.h&gt;
    #ifndef __cplusplus
    typedef unsigned char bool;
    #endif
    
    /* External Global Variable Declarations */
    
    /* Function Declarations */
    uint8_t* malloc(uint64_t);
    uint64_t atol(uint8_t*);
    void free(uint8_t*);
    int main(int, char **);
    void func0(uint8_t**, uint8_t**, uint8_t*, uint64_t, uint8_t);
    
    /* Global Variable Definitions and Initialization */
    uint64_t* args;
    uint32_t num_args = 3;
    
    /* Function Bodies */
    
    void init(uint32_t _1, uint8_t** argv) {
         args = (uint64_t*) malloc(num_args * sizeof(uint64_t));
         for (int i = 1; i &lt;= 3; ++i) {
             args[i - 1] = atol(argv[i]);
         }
         
         uint8_t *p = (uint8_t*) malloc(4);
         free(p);
    }
    
    int main(int argc, char ** argv) {
      uint32_t ac = (uint32_t)argc;
      uint8_t** av = (uint8_t**)argv;
      uint64_t* v1;
      uint8_t v2;
      uint64_t* inptr;
      uint64_t input0;
      uint64_t* inptr1;
      uint64_t input1;
      uint64_t* inptr2;
      uint64_t input2;
      uint8_t v3;
      uint8_t v4;
      uint8_t* v5;
      uint8_t v6;
      uint8_t* v7;
      uint8_t v8;
      uint8_t v9;
      bool v10;
      bool v11;
      uint8_t v13;
      uint8_t v14;
      uint8_t* v15;
      uint8_t v16;
      uint8_t v17;
      bool v18;
      uint8_t v19;
      bool v20;
      uint64_t v21;
      bool v22;
      uint8_t v23;
      uint64_t v24;
      uint8_t* v25;
      uint8_t** v26;
      uint8_t** v27;
      uint8_t v28;
      uint8_t v29;
      uint8_t v30;
      bool v31;
      bool v32;
      uint64_t v33;
      bool v34;
      uint64_t v35;
      uint8_t v36;
      bool v37;
      bool v38;
      
      init(ac, av);
      v1 = args;
      inptr = (&amp;(*v1));
      input0 = *inptr;
      inptr1 = (&amp;v1[((int64_t)1)]);
      input1 = *inptr1;
      inptr2 = (&amp;v1[((int64_t)2)]);
      input2 = *inptr2;
      v7 = (&amp;v8);
      v37 = (input2) &gt;= (49);
      v38 = (166841049) &gt; (input1);
      v10 = (input0) &lt; (2067997187);
      v11 = (input1) &lt;= (618503425);
      v8 = 1;
      v7 = ((uint8_t*)/*NULL*/0); // null pointer
      v26 = ((uint8_t**)/*NULL*/0);
      v26 = (&amp;v25);
      v27 = v26;
      v6 = 138u;
      func0((&amp;v25), v27, (&amp;v6), 1, 1); // aliases &amp;v25 v27
      v28 = ((uint8_t)input2);
      v29 = (1 - v28);
      v4 = 137u;
      v31 = ((int64_t)input0) &lt; ((int64_t)2900235183);
      v32 = input1 == input2;
      if (v32) {
        goto block1;
      } else {
        goto block2;
      }
    
    block4:
      *v5 = 1;
      func0((&amp;v7), (&amp;v5), (&amp;v23), input1, 97u);
      goto exit;
    
    block3:
      if (input0 &gt;= 351170948) {
        goto block4;
      } else {
        goto block5;
      }
    
    block5:
      v7 = (&amp;v3);
      goto exit;
    
    block1:
      v22 = 1707955933 == input1;
      v5 = (&amp;v23);
      v20 = ((int8_t)v29) &gt; ((int8_t)13);
      goto block3;
    
    exit:
      v33 = *inptr;
      return 0;
      
    block2:
      v7 = (&amp;v4);
      v34 = v29 == 101u;
      goto block1;
    }
    
    
    void func0(uint8_t** a1, uint8_t** a2, uint8_t* a3, uint64_t a4, uint8_t a5) {
      uint64_t v1;
      uint8_t v2;
      uint64_t v3;
      uint8_t v4;
      uint64_t v5;
      uint8_t v6;
      uint8_t* bugptr;
      uint8_t bug;
      uint64_t v7;
      uint64_t v8;
      uint8_t v9;
      bool v10;
      uint8_t v11;
      uint64_t v12;
      uint8_t v13;
      uint64_t v14;
      bool v15;
    
      v3 = 0;
      v4 = *a3;
      v5 = ((int64_t)(int8_t)v4);
      goto block1;
    
    block5:
      v2 = v4;
      bugptr = *a1;
      bug = *bugptr; // null dereference
      v6 = bug;
      goto exit;
    
    block4:
      v7 = v3;
      v8 = v7 ^ v12;
      v2 = v4;
      v9 = ((uint8_t)v8);
      v10 = ((int8_t)v4) &lt; ((int8_t)v9);
      if (v10) {
        goto block6;
      } else {
        goto block5;
      }
      
    block6:
      v3 = 2;
      goto exit;
    
    block2:
      v11 = *a3;
      v12 = ((int64_t)(int8_t)v11);
      goto block4;
    
    block1:
      *a2 = (&amp;v2);
      v13 = *a3;
      v14 = ((int64_t)(int8_t)v13);
      v15 = v5 &lt;= v14;
      if (v15) {
        goto block2;
      } else {
        goto block3;
      }
    
    exit:
      return;
      
    block3:
      v3 = 1;
      goto block2;
    }

@necto
Copy link
Contributor

necto commented Sep 24, 2024

Here is a reduced example (v37 = (input2) >= (49); line is preserved, removing it unblocks the null-ptr dereference report):

#include <stdint.h>
uint64_t *args;
char func0_v10, func0_v15;
void func0();
void top() {
  uint64_t *v1;
  uint64_t *inptr;
  uint64_t input0;
  uint64_t *inptr1;
  uint64_t input1;
  uint64_t *inptr2;
  uint64_t input2;
  uint8_t v4;
  uint8_t v5;
  uint8_t *v7 = 0;
  char v32, v37;
  v1 = args;
  inptr = v1;
  input0 = *inptr;
  inptr1 = &v1[1];
  input1 = *inptr1;
  inptr2 = &v1[2];
  input2 = *inptr2;
  v37 = (input2) >= (49);
  1049 > input1;
  input0 < 2067997187;
  func0();
  v32 = input1 == input2;
  if (v32)
    goto block1;
  goto block2;
block4:
  func0(&v7, &v5);
block3:
  goto block4;
block1:
  707955933 == input1;
  goto block3;
block2:
  v7 = &v4;
  goto block1;
}
void func0(uint8_t **a1, uint8_t **a2) {
  uint8_t v2;
  uint8_t *bugptr;
  goto block1;
block5:
  bugptr = *a1;
  *bugptr;
  goto exit;
block4:
  if (func0_v10)
    ;
  goto block5;
block6:
block2:
  goto block4;
block1:
  *a2 = &v2;
  if (func0_v15)
    goto block2;
  goto block3;
exit:
block3:
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants