review unknown code with static analysis - bredaphp

48
Review unknown code with static analysis Breda, Nederlands, Dec. 2016

Upload: damien-seguy-

Post on 26-Jan-2017

91 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Review unknown code with static analysis - bredaphp

Review unknown code with static analysis

Breda, Nederlands, Dec. 2016

Page 2: Review unknown code with static analysis - bredaphp

Agenda

Reviewing code

Static analysis for PHP

A session in which you are the hero

Page 3: Review unknown code with static analysis - bredaphp

Review this project

We don't know what it does

We have never heard about it

We don't run it

We don't know the authors

Can we have an opinion?

Page 4: Review unknown code with static analysis - bredaphp

How to review code

Reading code is humanly possible : its an art

Unit test are not adapted for review

Dynamic analysis is not fit for review

We need to explore code

we cannot only rely on the current state

Page 5: Review unknown code with static analysis - bredaphp

Speaker

Damien Seguy

Exakat CTO

Den Haag : ik ben een boterham

Static analysis for PHP : SCAP

PHP doc author

Page 6: Review unknown code with static analysis - bredaphp

Source code is structured

Source code is a structured database

All we need is tools to query it

This is static analysis

Page 7: Review unknown code with static analysis - bredaphp

Migration PHP 7.0->7.1

Inco

mpa

tibilit

iesNe

w fe

atur

es

Page 8: Review unknown code with static analysis - bredaphp

PHP LINT

php -l <fichier.php>

Paralell executions

jakub-onderka/php-paralell-lint

Various versions of PHP : 7.0, 7.1, 7.2, 5.6, 5.5

Page 9: Review unknown code with static analysis - bredaphp

Checked 5982 files in 28.4 seconds Syntax error found in 4 files

------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/False.php:22 20| * @api 21| */ > 22| class False extends IsFalse 23| { 24| } Fatal error: Cannot use 'False' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/Null.php:22 20| * @api 21| */ > 22| class Null extends IsNull 23| { 24| } Fatal error: Cannot use 'Null' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/True.php:22 20| * @api 21| */ > 22| class True extends IsTrue 23| { 24| } Fatal error: Cannot use 'True' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor_user/windid_client/src/windid/service/base/WindidUtility.php:93 91| $imageInfo = @getimagesize($file); 92| $exts = array('1'=>'gif', '2'=>'jpg', '3'=>'png'); > 93| if (!isset($exts[$imageInfo[2]])) continue; 94| $ext = $exts[$imageInfo[2]]; 95| $filename = rand(1000,9999). '.'.$ext; Fatal error: 'continue' not in the 'loop' or 'switch' context

PHP LINT - 7.0/1/2

Page 10: Review unknown code with static analysis - bredaphp

Checked 5982 files in 29.7 seconds Syntax error found in 1 file

------------------------------------------------------------ Parse error: /vendor2/mockery/mockery/tests/Mockery/MockingVariadicArgumentsTest.php:52 50| abstract class TestWithVariadicArguments 51| { > 52| public function foo(...$bar) 53| { 54| return $bar; Unexpected '.', expecting '&' or variable (T_VARIABLE)

PHP LINT - 5.5

PHP LINT - 5.6Checked 5982 files in 31 seconds No syntax error found

Page 11: Review unknown code with static analysis - bredaphp

PHP LINT

Not compatible with PHP 7.0 +

Not compatible with PHP 5.5-

Uses Symfony

@getimagesize ? vendor2 ?

5982 files

Page 12: Review unknown code with static analysis - bredaphp

Metrics

PHPloc, PHPmetrics, PHP MD

Provides global values about the code

Cyclomatic complexity, LOC…

Page 13: Review unknown code with static analysis - bredaphp

PHPLOC Directories 1143 Files 5982

Size Lines of Code (LOC) 835199 Comment Lines of Code (CLOC) 252075 (30.18%) Non-Comment Lines of Code (NCLOC) 583124 (69.82%) Logical Lines of Code (LLOC) 195283 (23.38%) Classes 178062 (91.18%) Average Class Length 29 Minimum Class Length 0 Maximum Class Length 3141 Average Method Length 4 Minimum Method Length 0 Maximum Method Length 879 Functions 1477 (0.76%) Average Function Length 1 Not in classes or functions 15744 (8.06%)

Cyclomatic Complexity Average Complexity per LLOC 0.30 Average Complexity per Class 10.82 Minimum Class Complexity 1.00 Maximum Class Complexity 1177.00 Average Complexity per Method 2.65 Minimum Method Complexity 1.00 Maximum Method Complexity 387.00

[...]

Page 14: Review unknown code with static analysis - bredaphp

PHPLOC Dependencies Global Accesses 2158 Global Constants 1738 (80.54%) Global Variables 31 (1.44%) Super-Global Variables 389 (18.03%) Attribute Accesses 50986 Non-Static 49206 (96.51%) Static 1780 (3.49%) Method Calls 113735 Non-Static 103683 (91.16%) Static 10052 (8.84%)

Structure Namespaces 851 Interfaces 693 Traits 11 Classes 5245 Abstract Classes 301 (5.74%) Concrete Classes 4944 (94.26%) Methods 39581 Scope Non-Static Methods 37468 (94.66%) Static Methods 2113 (5.34%) Visibility Public Methods 31500 (79.58%) Non-Public Methods 8081 (20.42%) Functions 1185 Named Functions 306 (25.82%) Anonymous Functions 879 (74.18%) Constants 2658 Global Constants 361 (13.58%) Class Constants 2297 (86.42%)

Page 15: Review unknown code with static analysis - bredaphp

PHPMetrics

Page 16: Review unknown code with static analysis - bredaphp

PHPMetrics

Page 17: Review unknown code with static analysis - bredaphp

Automated code review

PHP code review PHP code

regex reads PHP

Extract interesting points

Works with keywords

PHP7cc, grep

Page 18: Review unknown code with static analysis - bredaphp

php7ccFile: /vendor_user/windid_client/wind/convert/WindGeneralConverter.php > Line 33: PHP 4 constructors are now deprecated public function WindGeneralConverter($sourceLang = '', $targetLang = '', $forceTable = false) { }

File: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/Null.php > Line 22: Reserved name "null" used as a class, interface or trait name class Null extends \Symfony\Component\Validator\Constraints\IsNull { }

File: /vendor_user/windid_client/wind/filter/WindHandlerInterceptorChain.php > Line 61: Function argument(s) returned by "func_get_args" might have been modified func_get_args();

File: /vendor_user/windid_client/wind/http/session/handler/WindSessionHandler.php > Line 156: Check that callbacks that are passed to "session_set_save_handler" and return false or -1 (if any) operate correctly session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc'));

File: /vendor_user/windid_client/wind/security/WindMcryptCbc.php > Line 31: Removed function "mcrypt_cbc" called mcrypt_cbc(MCRYPT_DES, $key, $string, MCRYPT_ENCRYPT, $iv); > Line 49: Removed function "mcrypt_cbc" called mcrypt_cbc(MCRYPT_DES, $key, $string, MCRYPT_DECRYPT, $iv);

Total : 83 issues

Page 19: Review unknown code with static analysis - bredaphp

Automated code review

Semantic read of the code

Reports interesting issues

Works with AST

PHP7mar, Phan, exakat

Page 20: Review unknown code with static analysis - bredaphp

Automated code review

PHP 5 / 7 Calisthenics ClearPHP

Performance

Page 21: Review unknown code with static analysis - bredaphp

AST

<?php

class Foo { function bar($arg) { return \StrToUpper($arg + 2); } }

$foo = new Foo(); $foo->bar(__FILE__);

?>

Page 22: Review unknown code with static analysis - bredaphp

Semantics and definitions

PHP7mar : nikic/php5-ast

PHAN : ext/ast (PHP 7 only)

Exakat : AST in a graph database

SonarQube : Java-build AST

PHPstorm : internal IDE AST

Page 23: Review unknown code with static analysis - bredaphp

Semantics and definitions

Removes spaces, comments, documentations

Removes delimiters

( ) { } [ ] " ' ` ; :

Good network to link definition with usage

Page 24: Review unknown code with static analysis - bredaphp

PHANsrc/Org/OrgBundle/Controller/OrgController.php:12 PhanTypeMismatchArgument Argument 1 (data) is bool but \Org\OrgBundle\Controller\OrgController::createJsonResponse() takes array defined at src/Topxia/WebBundle/Controller/BaseController.php:120

Total : 13315 results1235 issues

vendor_user/windid_client/wind/mail/protocol/WindPop3.php:186 PhanUndeclaredTypeParameter Parameter of undeclared type \baoolean

276 issues

vendor_user/windid_client/wind/base/WindFactory.php:325 PhanTypeArraySuspicious Suspicious array access to bool

184 issues

vendor2/imagine/imagine/lib/Imagine/Image/AbstractLayers.php:49 PhanParamSignatureMismatch Declaration of function get($offset) should be compatible with function get(int $offset) : \Imagine\Image\ImageInterface defined in vendor2/imagine/imagine/lib/Imagine/Image/LayersInterface.php:97

src/Classroom/ClassroomBundle/Controller/ClassroomAdminController.php:84 PhanUndeclaredMethod Call to undeclared method \Classroom\ClassroomBundle\Controller \ClassroomAdminController::createErrorResponse

1919 issues

808 issues

Page 25: Review unknown code with static analysis - bredaphp

PHAN [PhanRedefineFunction] => 31 [PhanTypeMismatchForeach] => 31 [PhanUndeclaredClassInstanceof] => 32 [PhanDeprecatedFunction] => 43 [PhanUndeclaredClassConstant] => 49 [PhanUndeclaredTypeProperty] => 60 [PhanParamSignatureMismatchInternal] => 79 [PhanUndeclaredClassCatch] => 94 [PhanParamTooMany] => 101 [PhanUndeclaredFunction] => 102 [PhanTypeMissingReturn] => 126 [PhanStaticCallToNonStatic] => 164 [PhanTypeArraySuspicious] => 184 [PhanTypeMismatchDefault] => 194 [PhanNonClassMethodCall] => 202 [PhanUndeclaredTypeParameter] => 276 [PhanUndeclaredConstant] => 417 [PhanUndeclaredVariable] => 432 [PhanTypeMismatchProperty] => 530 [PhanUndeclaredMethod] => 808 [PhanTypeMismatchArgumentInternal] => 854 [PhanUndeclaredClassMethod] => 1082 [PhanTypeMismatchReturn] => 1236 [PhanTypeMismatchArgument] => 1716 [PhanParamSignatureMismatch] => 1840 [PhanUndeclaredProperty] => 2485

53 analyses

Page 26: Review unknown code with static analysis - bredaphp

PHANsrc/Classroom/Service/Classroom/Tests/ClassroomReviewServiceTest.php:227 PhanDeprecatedFunction Call to deprecated function \Classroom\Service\Classroom\Tests\ClassroomReviewServiceTest::setExpectedException()

defined at vendor/phpunit/phpunit/src/Framework/TestCase.php:466

43 issues

Page 27: Review unknown code with static analysis - bredaphp

PHP 7 helps SCAP

Type hint, return type hint, scalar typehint

Phan understands PHPDOC

Dynamic code is very difficult to analyze

Page 28: Review unknown code with static analysis - bredaphp

Flow Control diagram

Handle the way the code is executed

Based on AST, adds sequence tracking

Applied in RIPS

Page 29: Review unknown code with static analysis - bredaphp

<?php     $x = source();          if ($x < 10) {         $y = $x + 1;         $x = corrige($y);     } else {         $y = $x;     }

Page 30: Review unknown code with static analysis - bredaphp

Flow Control Graph

$x = source();

if ($x < 10) 

$y = $x + 1;

$x = corrige($y);

$y = $x;

PHP

Exit

ElseThen

<?php     $x = source();          if ($x < 10) {         $y = $x + 1;         $x = corrige($y);     } else {         $y = $x;     }

Page 31: Review unknown code with static analysis - bredaphp

Program Dependency Graph

$x = source();

if ($x < 10) 

$y = $x + 1;

$x = corrige($y);

$y = $x;Depend de $x

Depend de $x

Depend de $y

Depend de $x

Depend de $x

Depend de $x

<?php     $x = source();          if ($x < 10) {         $y = $x + 1;         $x = corrige($y);     } else {         $y = $x;     }

Page 32: Review unknown code with static analysis - bredaphp
Page 33: Review unknown code with static analysis - bredaphp

What about PHP?

Most of those analysis focus on informatics concepts

Some analysis focus on PHP's specifics

Common practices

Special PHP gotchas

Page 34: Review unknown code with static analysis - bredaphp

Exakat analysisfunction __destruct() { throw …} : 0,5%

function foo($a, $a, $a) {} : 0,5%

!!(expression) : 7.4%

substr($a, 2, 4) == 'abc' : 9 %

$a ? $b ? $c : $d : $e ; 10%

foreach($a as &$b) {} : 21%

if (strpos($a, $b)) {} : 51 %

include('file.php') : 52%

Page 35: Review unknown code with static analysis - bredaphp

Clean code for PHP

Best practices

in-house, PSR, calisthenics, other inspirations

Code mantras, code kata

PHP Manual

Migration guides

Page 36: Review unknown code with static analysis - bredaphp

PHP

List of used PHP features

Page 37: Review unknown code with static analysis - bredaphp

PHP

List of directives

Page 38: Review unknown code with static analysis - bredaphp

Project preferences

List of directives

Page 39: Review unknown code with static analysis - bredaphp

What does this app do?

Welcome to the inventories

List of literal in the code

Integers, real, arrays, strings

Names for classes, methods, traits, variables, interfaces…

Page 40: Review unknown code with static analysis - bredaphp

Error

String used with exit, die and new Exception()

Page 41: Review unknown code with static analysis - bredaphp

Variables

$orderBy 685 $token 690 $response 721 $paginator 752 $temp 828 $params 891 $value 925 $type 955 $thread 968 $order 982 $member 1042 $classroom 1115 $limit 1222 $start 1320 $currentUser 1334 $userId 1352 $file 1391 $data 1408 $i 1494 $lesson 1504 $sql 1528 $courseId 1626 $key 1716 $fields 2214 $result 2600 $course 2742 $request 3219 $id 3529 $conditions 3870 $user 4505

Also : 271 used-once variables

Page 42: Review unknown code with static analysis - bredaphp

ClassesOrderServiceTest 2 FileController 2 ClassroomDataTag 2 LiveCourseController 2 UploadFileController 2 NoteController 2 BlockController 2 OrderLogDaoImpl 2 OpenCourseController 2 FileFilter 2 CourseOrderController 2 Member 2 CoinController 2 ThreadServiceTest 3 BaseProcessor 3 MobileController 3 UserController 3 CategoryDaoImpl 3 CourseReviewController 3 TeacherController 3 AlipaySubmit 3 ThreadServiceImpl 3 ThreadPostDaoImpl 3 AlipayNotify 3 ThreadDaoImpl 3 CourseController 5 DefaultController 5 DefaultControllerTest 5 Configuration 6

Page 43: Review unknown code with static analysis - bredaphp

Comparisons

none 9 vip 10 .. 10 yes 10 material 11 coin 11 created 11 teacher 12 closed 12 error 13 1 14 RMB 15 0 16 paid 16 lesson 18 liveOpen 19 trend 19 cloud 19 ok 20 Coin 21 classroom 22 video 25 self 25 testpaper 27 success 32 live 32 course 39 published 43 _empty_ 71 POST 237

Strings used in comparisons $a == 'ok'

Occurrences counts

Page 44: Review unknown code with static analysis - bredaphp

Going further

Deptrac

Check that classes stay within their layer

Manual configuration

Until frameworks define layers

Page 45: Review unknown code with static analysis - bredaphp

Going even furtherDynamic code

40% of the code is actually constant

Transpilage : https://github.com/jaytaph/Transphpile

PHP inspections : Integrated in phpStorm

sensio labs insight : Static analysis for Symfony

Integrate static analysis in IC

Page 46: Review unknown code with static analysis - bredaphp

Liste des SCAP citésDeptrac

Exakat

PHP7mar

Phan

PHP Inspections

Phploc

PHPMD

PHP 7 cc

PHPmetrics

RIPS

Transphpile

Page 47: Review unknown code with static analysis - bredaphp

Edusoho

Page 48: Review unknown code with static analysis - bredaphp

Bedankt!http://exakat.io/ - @exakat

https://joind.in/talk/d5b2c