11cb0ef41Sopenharmony_ciDESCRIPTION ------------------------------------------------------------------- 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_cigcmole is a simple static analysis tool used to find possible evaluation order 41cb0ef41Sopenharmony_cidependent GC-unsafe places in the V8 codebase and "stale" pointers to the heap 51cb0ef41Sopenharmony_ci(ones whose addresses got invalidated by the GC). 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciFor example the following code is GC-unsafe: 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci Handle<Object> Foo(); // Assume Foo can trigger a GC. 101cb0ef41Sopenharmony_ci void Bar(Object, Object); 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci Handle<Object> baz; 131cb0ef41Sopenharmony_ci baz->Qux(*Foo()); // (a) 141cb0ef41Sopenharmony_ci Bar(*Foo(), *baz); // (b) 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ciBoth in cases (a) and (b) compiler is free to evaluate call arguments (that 171cb0ef41Sopenharmony_ciincludes receiver) in any order. That means it can dereference baz before 181cb0ef41Sopenharmony_cicalling to Foo and save a raw pointer to a heap object in the register or 191cb0ef41Sopenharmony_cion the stack. 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ciIn terms of the AST analysis that gcmole does, it warns about places in the 221cb0ef41Sopenharmony_cicode which result in 2 subtrees, the order of execution of which is undefined 231cb0ef41Sopenharmony_ciby C++, one of which causes a GC and the other dereferences a Handle to a raw 241cb0ef41Sopenharmony_ciObject (or its subclasses). 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciThe following code triggers a stale variable warning (assuming that the Foo 271cb0ef41Sopenharmony_cifunction was detected as potentially allocating, as in the previous example): 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci JSObject raw_obj = ...; 301cb0ef41Sopenharmony_ci Foo(); 311cb0ef41Sopenharmony_ci raw_obj.Print(); 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciSince Foo can trigger a GC, it might have moved the raw_obj. The solution is 341cb0ef41Sopenharmony_cisimply to store it as a Handle. 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciPREREQUISITES ----------------------------------------------------------------- 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci(1) Install Python 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci $ sudo apt-get install python 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci(2) Get LLVM 8.0 and Clang 8.0 sources and build them. 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci Follow the instructions on http://clang.llvm.org/get_started.html. 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci Make sure to pass -DCMAKE_BUILD_TYPE=Release to cmake to get Release build 471cb0ef41Sopenharmony_ci instead of a Debug one. 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci(3) Build gcmole Clang plugin (libgcmole.so) 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci In the tools/gcmole directory execute the following command: 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci $ BUILD_ROOT=<path> LLVM_SRC_ROOT=<path> CLANG_SRC_ROOT=<path> make 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci(*) Note that steps (2) and (3) can also be achieved by just using the included 561cb0ef41Sopenharmony_ci bootstrapping script in this directory: 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci $ ./tools/gcmole/bootstrap.sh 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci This will use "third_party/llvm+clang-build" as a build directory and checkout 611cb0ef41Sopenharmony_ci required sources in the "third_party" directory. 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ciUSING GCMOLE ------------------------------------------------------------------ 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_cigcmole consists of driver script written in Python and Clang plugin that does 661cb0ef41Sopenharmony_ciC++ AST processing. Plugin (libgcmole.so) is expected to be in the same 671cb0ef41Sopenharmony_cifolder as driver (gcmole.py). 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciTo start analysis cd into the root of v8 checkout and execute the following 701cb0ef41Sopenharmony_cicommand: 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ciCLANG_BIN=<path-to-clang-bin-folder> python tools/gcmole/gcmole.py [<arch>] 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ciwhere arch should be one of architectures supported by V8 (arm, ia32, x64). 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ciAnalysis will be performed in 2 stages: 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci- on the first stage driver will parse all files and build a global callgraph 791cb0ef41Sopenharmony_ciapproximation to find all functions that might potentially cause GC, list 801cb0ef41Sopenharmony_ciof this functions will be written into gcsuspects file. 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci- on the second stage driver will parse all files again and will locate all 831cb0ef41Sopenharmony_cicallsites that might be GC-unsafe based on the list of functions causing GC. 841cb0ef41Sopenharmony_ciSuch places are marked with a "Possible problem with evaluation order." 851cb0ef41Sopenharmony_ciwarning. Messages "Failed to resolve v8::internal::Object" are benign and 861cb0ef41Sopenharmony_cican be ignored. 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciIf any errors were found driver exits with non-zero status. 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ciTESTING ----------------------------------------------------------------------- 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ciTests are automatically run by the main python runner. Expectations are in 931cb0ef41Sopenharmony_citest-expectations.txt and need to be updated whenever the sources of the tests 941cb0ef41Sopenharmony_ciin gcmole-test.cc are modified (line numbers also count). 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ciPACKAGING --------------------------------------------------------------------- 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_cigcmole is deployed on V8's buildbot infrastructure to run it as part of the 991cb0ef41Sopenharmony_cicontinuous integration. A pre-built package of gcmole together with Clang is 1001cb0ef41Sopenharmony_cihosted on Google Cloud Storage for this purpose. To update this package to a 1011cb0ef41Sopenharmony_cinewer version, use the provided packaging script: 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci $ ./tools/gcmole/package.sh 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciThis will create a new "tools/gcmole/gcmole-tools.tar.gz" package with the 1061cb0ef41Sopenharmony_cicorresponding SHA1 sum suitable to be used for this purpose. It assumes that 1071cb0ef41Sopenharmony_ciClang was built in "third_party/llvm+clang-build" (e.g. by the bootstrapping 1081cb0ef41Sopenharmony_ciscript "bootstrap.sh" mentioned above). 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ciTROUBLESHOOTING --------------------------------------------------------------- 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_cigcmole is tightly coupled with the AST structure that Clang produces. Therefore 1131cb0ef41Sopenharmony_ciwhen upgrading to a newer Clang version, it might start producing bogus output 1141cb0ef41Sopenharmony_cior completely stop outputting warnings. In such occasion, one might start the 1151cb0ef41Sopenharmony_cidebugging process by checking weather a new AST node type is introduced which 1161cb0ef41Sopenharmony_ciis currently not supported by gcmole. Insert the following code at the end of 1171cb0ef41Sopenharmony_cithe FunctionAnalyzer::VisitExpr method to see the unsupported AST class(es) 1181cb0ef41Sopenharmony_ciand the source position which generates them: 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci if (expr) { 1211cb0ef41Sopenharmony_ci clang::Stmt::StmtClass stmtClass = expr->getStmtClass(); 1221cb0ef41Sopenharmony_ci d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_), 1231cb0ef41Sopenharmony_ci d_.getCustomDiagID(clang::DiagnosticsEngine::Remark, "%0")) << stmtClass; 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ciFor instance, gcmole currently doesn't support AtomicExprClass statements 1271cb0ef41Sopenharmony_ciintroduced for atomic operations. 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ciA convenient way to observe the AST generated by Clang is to pass the following 1301cb0ef41Sopenharmony_ciflags when invoking clang++ 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci -Xclang -ast-dump -fsyntax-only 133