Static code analysis: what? how? why?

Andrey_Karpov 60 views 36 slides Jun 15, 2021
Slide 1
Slide 1 of 36
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36

About This Presentation

From code review to static code analysis. Static code analysis techniques. Some examples of defects in real projects. C, C++, C#, Java.


Slide Content

Static code analysis: what ? how ? why ? Maxim Stefanov PVS-Studio, C++ / Java developer, Tula 1

About The Speaker Maxim Stefanov ( [email protected] ) C++/Java developer in PVS-Studio Duties: Develops C++ core of the analyzer Develops Java analyzer 2

Theory The importance of code quality ( bugs , vulnerabilities, ... ) Defect prevention methods From code review to static code analysis Code review VS Static code analysis Static code analysis techniques Some examples of defects in real projects More about static analysis Summary 3 We’ll Talk About ...

Perception Enhancement Support Absence of bugs ... et cetera 4 High-Quality Code

It prevents technical debt if the project is new It helps not to lose users if the project is mature 5 Why Is Code Quality Important?

Cost to Fix a Defect

Helps to find high-level bugs without shooting yourself in the foot Allows to share experience with padawans Together you’ll learn some new things about the project and its secrets 7 Code review

Code review is very expensive : Expectation : « We’ll review this edit for 10-15 min » Reality – sometimes code review takes hours You get tired quickly 8 But ...

Pros Cons Finds defects before code review You can’t find high-level errors An analyzer can’t get tired, it’s ready to work at any time False positives You can find errors without even knowing about such a pattern You can find errors which are difficult to notice 9 Static Code Analysis Comes to Rescue

P attern-based analysis Type inference Method annotations D ata-flow analysis Symbolic execution 10 Static Code Analysis Techniques

@ Override public boolean equals ( Object obj ) { .... return index.equals ( other.index ) && type.equals ( other.type ) && version == other.version && found == other.found && tookInMillis == tookInMillis && Objects. equals ( terms , other.terms ); } 11 P attern-based analysis

Type inference interface Human { ... . } class Parent implements Human { .. . . } class Child extends Parent { ... . } .... class Animal { ... } .... boolean someMethod ( List < Child > list , Animal animal ) { if ( list.remove ( animal ) ) return false ; .. . . } 12

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 13

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 14

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 15

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 16

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 17

Method annotations Class (" java.lang.Math " ) - Function ( " max " , Type ::Int32, Type ::Int32) . Pure () . Set ( FunctionClassification :: NoDiscard ) . Requires ( NotEquals (Arg1, Arg2)) . Returns (Arg1, Arg2,[]( const Int &v1, const Int &v2) { return v1.Max(v2); }) 18

int test ( int a, int b) { .... Math. max (a, b ); .... } 19 Method annotations

int test ( int a, int b) { .... return Math. max (a, a) ; } 20 Method annotations

int test ( int a, int b) { if (a > 5 && b < 2) { // a = [6..INT_MAX] // b = [INT_MIN..1] if ( Math. max (a, b) > 0 ) { ....} } .... } 21 Method annotations

D ata-flow analysis void func ( int x) { // x: [-2147483648..2147483647] //1 if (x > 3) { // x: [4..2147483647] //2 if (x < 10) { // x: [4..9] //3 } } else { // x: [-2147483648..3] //4 } } 22

Symbolic execution int someMethod ( int A, int B) { if (A == B) return 10 / (A - B) ; return 1; } 23

Some Examples of Defects in Real Projects 24

PUGI__FN bool set_value_convert ( char_t *& dest , uintptr_t & header, uintptr_t header_mask , int value) { char buf [128]; sprintf ( buf , "%d", value); return set_value_buffer ( dest , header, header_mask , buf ); } StarEngine , C++ PVS-Studio: V614 Uninitialized buffer ' buf ' used . pugixml.cpp 3362 It Came Up Unexpectedly ... 25

It Came Up Unexpectedly ... PUGI__FN bool set_value_convert ( char_t *& dest , uintptr_t & header, uintptr_t header_mask , int value) { char buf [128]; sprintf ( buf , "%d", value); return set_value_buffer ( dest , header, header_mask , buf ); } PVS-Studio: V614 Uninitialized buffer ' buf ' used . pugixml.cpp 3362 #define schar char #define suchar unsigned schar #define sprintf std :: printf #define satof atof #define satoi atoi 26 StarEngine , C++

PVS-Studio: V6007 Expression ' StringUtils.isNotEmpty (" handleTabKey ")' is always true. SourceCodeEditorLoader.java 60 Copy Paste public void loadComponent () { .... String handleTabKey = element.attributeValue ( " handleTabKey " ); if ( StringUtils.isNotEmpty ( " handleTabKey " )) { resultComponent.setHandleTabKey (....); } .... } 27 CUBA Platform , Java

V778 Two similar code fragments were found. Perhaps, this is a typo and ' cap_resy ' variable should be used instead of ' cap_resx '. cyapa.c 1458 Copy Paste static int cyapa_raw_input ( struct cyapa_softc * sc , ....) { .... if ( sc -> delta_x > sc -> cap_resx ) sc -> delta_x = sc -> cap_resx ; if ( sc -> delta_x < - sc -> cap_resx ) sc -> delta_x = - sc -> cap_resx ; if ( sc -> delta_y > sc -> cap_resx ) sc -> delta_y = sc -> cap_resy ; if ( sc -> delta_y < - sc -> cap_resy ) sc -> delta_y = - sc -> cap_resy ; .... } 28 FreeBSD Kernel , C

V778 Two similar code fragments were found. Perhaps, this is a typo and ' cap_resy ' variable should be used instead of ' cap_resx '. cyapa.c 1458 Copy Paste static int cyapa_raw_input ( struct cyapa_softc * sc , ....) { .... if ( sc -> delta_ x > sc -> cap_res x ) sc -> delta_ x = sc -> cap_res x ; if ( sc -> delta_ x < - sc -> cap_res x ) sc -> delta_ x = - sc -> cap_res x ; if ( sc -> delta_ y > sc -> cap_res x ) sc -> delta_ y = sc -> cap_res y ; if ( sc -> delta_ y < - sc -> cap_res y ) sc -> delta_ y = - sc -> cap_res y ; .... } 29 FreeBSD Kernel , C

char c; printf( "%s .... "); rewind( blk_alloc_file ); while ( (c = fgetc ( blk_alloc_file )) != EOF ) { fputc (c, base_fs_file ); } Android , C PVS-Studio: V739 CWE-20 EOF should not be compared with a value of the 'char' type. The '(c = fgetc ( blk_alloc_file ))' should be of the ' int ' type. blk_alloc_to_base_fs.c 61 30 Unlucky Character

Compiler Deletes Code to Wipe Buffer static void FwdLockGlue_InitializeRoundKeys () { unsigned char keyEncryptionKey [KEY_SIZE]; .... memset ( keyEncryptionKey , 0, KEY_SIZE); // Zero out key data. } PVS-Studio: V597 CWE-14 The compiler could delete the ' memset ' function call , which is used to flush ' keyEncryptionKey ' buffer . The memset_s () function should be used to erase the private data . FwdLockGlue.c 102 31 Android , C

How to Blend Static Analysis into Software Development Process Every developer has a static analysis tool in their workplace Analysis of the entire codebase during night builds. If suspicious code is found, the guilty one will receive an email 32

How to Start Using Static Analysis Tools in Big Projects and Keep Your Cool Check the project Put all issued warnings in a special suppression file to indicate that now you are not interested in all issued warnings Put the markup file into the version control system Run the analyzer and receive warnings only for new or changed code PROFIT! 33

Summary Static analysis helps to immediately find some errors while the cost to fix them is low Static analysis should be used regularly You can start using the analysis right away and fix some old errors after Static analysis is not a silver bullet, it’s important to use different techniques 34

Thank you for your attention ! 35

Useful Links The podcast about static analysis with PVS-Studio founders [RU] The list of static analysis tools The PVS-Studio site