Bug 1440886 - Implement a static analysis checker to detect usage of PR_LoadLibrary and LoadLibraryA/LoadLibraryExA/LoadLibrary/LoadLibraryEx. r?mystor
authorAndi-Bogdan Postelnicu <bpostelnicu@mozilla.com>
Wed, 07 Mar 2018 14:36:44 +0200
changeset 1504648 35b1872e31e878feaceee8e3753d00a81d27a161
parent 1504483 2a4b0d1e9a8e9c9ffe48d3a6a09e6ac7b78ee71a
child 1504649 2c86f05cd3744fa38b06d9377071d99bea525301
push id269796
push userbpostelnicu@mozilla.com
push dateMon, 07 May 2018 14:23:20 +0000
treeherdertry@2c86f05cd374 [default view] [failures only]
reviewersmystor
bugs1440886
milestone61.0a1
Bug 1440886 - Implement a static analysis checker to detect usage of PR_LoadLibrary and LoadLibraryA/LoadLibraryExA/LoadLibrary/LoadLibraryEx. r?mystor MozReview-Commit-ID: CUjfeBeOdsk
build/clang-plugin/Checks.inc
build/clang-plugin/ChecksIncludes.inc
build/clang-plugin/LoadLibraryUsageChecker.cpp
build/clang-plugin/LoadLibraryUsageChecker.h
build/clang-plugin/Utils.h
build/clang-plugin/moz.build
build/clang-plugin/tests/TestLoadLibraryUsage.cpp
build/clang-plugin/tests/moz.build
tools/rewriting/ThirdPartyPaths.txt
--- a/build/clang-plugin/Checks.inc
+++ b/build/clang-plugin/Checks.inc
@@ -6,16 +6,19 @@
 
 CHECK(ArithmeticArgChecker, "arithmetic-argument")
 CHECK(AssertAssignmentChecker, "assignment-in-assert")
 CHECK(CanRunScriptChecker, "can-run-script")
 CHECK(DanglingOnTemporaryChecker, "dangling-on-temporary")
 CHECK(ExplicitImplicitChecker, "implicit-constructor")
 CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool")
 CHECK(KungFuDeathGripChecker, "kungfu-death-grip")
+#ifdef _WIN32
+CHECK(LoadLibraryUsageChecker, "load-library-usage")
+#endif
 CHECK(MustOverrideChecker, "must-override")
 CHECK(MustReturnFromCallerChecker, "must-return-from-caller")
 CHECK(MustUseChecker, "must-use")
 CHECK(NaNExprChecker, "nan-expr")
 CHECK(NeedsNoVTableTypeChecker, "needs-no-vtable-type")
 CHECK(NoAddRefReleaseOnReturnChecker, "no-addref-release-on-return")
 CHECK(NoAutoTypeChecker, "no-auto-type")
 CHECK(NoDuplicateRefCntMemberChecker, "no-duplicate-refcnt-member")
--- a/build/clang-plugin/ChecksIncludes.inc
+++ b/build/clang-plugin/ChecksIncludes.inc
@@ -6,16 +6,19 @@
 // are compatible with clang-tidy.
 
 #include "ArithmeticArgChecker.h"
 #include "AssertAssignmentChecker.h"
 #include "CanRunScriptChecker.h"
 #include "DanglingOnTemporaryChecker.h"
 #include "ExplicitImplicitChecker.h"
 #include "ExplicitOperatorBoolChecker.h"
+#ifdef _WIN32
+#include "LoadLibraryUsageChecker.h"
+#endif
 #include "KungFuDeathGripChecker.h"
 #include "MustOverrideChecker.h"
 #include "MustReturnFromCallerChecker.h"
 #include "MustUseChecker.h"
 #include "NaNExprChecker.h"
 #include "NeedsNoVTableTypeChecker.h"
 #include "NoAddRefReleaseOnReturnChecker.h"
 #include "NoAutoTypeChecker.h"
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/LoadLibraryUsageChecker.cpp
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "LoadLibraryUsageChecker.h"
+#include "CustomMatchers.h"
+
+// On MacOS the filesystem is UTF-8, on linux the canonical filename is 8-bit
+// string. On Windows data loss conversion will occur. This checker restricts
+// the use of ASCII file functions for loading libraries.
+
+void LoadLibraryUsageChecker::registerMatchers(MatchFinder *AstMatcher) {
+  AstMatcher->addMatcher(
+      callExpr(
+          allOf(isFirstParty(),
+                callee(functionDecl(anyOf(
+                    allOf(isInSystemHeader(), anyOf(hasName("LoadLibraryA"),
+                                                    hasName("LoadLibraryExA"))),
+                    hasName("PR_LoadLibrary")))),
+                unless(hasArgument(0, stringLiteral()))))
+          .bind("funcCall"),
+      this);
+}
+
+void LoadLibraryUsageChecker::check(const MatchFinder::MatchResult &Result) {
+  const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
+
+  if (FuncCall) {
+    diag(FuncCall->getLocStart(),
+         "Usage of ASCII file functions (such as %0) is forbidden.",
+         DiagnosticIDs::Error)
+        << FuncCall->getDirectCallee()->getName();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/LoadLibraryUsageChecker.h
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef LoadLibraryUsageChecker_h__
+#define LoadLibraryUsageChecker_h__
+
+#include "plugin.h"
+
+class LoadLibraryUsageChecker : public BaseCheck {
+public:
+  LoadLibraryUsageChecker(StringRef CheckName, ContextType *Context = nullptr)
+      : BaseCheck(CheckName, Context) {}
+  void registerMatchers(MatchFinder *AstMatcher) override;
+  void check(const MatchFinder::MatchResult &Result) override;
+};
+
+#endif // !defined(LoadLibraryUsageChecker_h__)
--- a/build/clang-plugin/Utils.h
+++ b/build/clang-plugin/Utils.h
@@ -423,18 +423,21 @@ inline CXXRecordDecl *getNonTemplateSpec
 
 inline bool inThirdPartyPath(const Decl *D) {
   return inThirdPartyPath(D, &D->getASTContext());
 }
 
 inline bool inThirdPartyPath(const Stmt *S, ASTContext *context) {
   SourceLocation Loc = S->getLocStart();
   const SourceManager &SM = context->getSourceManager();
-
-  return inThirdPartyPath(Loc, SM);
+  auto ExpansionLoc = SM.getExpansionLoc(Loc);
+  if (ExpansionLoc.isInvalid()) {
+    return inThirdPartyPath(Loc, SM);
+  }
+  return inThirdPartyPath(ExpansionLoc, SM);
 }
 
 /// Polyfill for CXXOperatorCallExpr::isInfixBinaryOp()
 inline bool isInfixBinaryOp(const CXXOperatorCallExpr *OpCall) {
 #if CLANG_VERSION_FULL >= 400
   return OpCall->isInfixBinaryOp();
 #else
   // Taken from clang source.
--- a/build/clang-plugin/moz.build
+++ b/build/clang-plugin/moz.build
@@ -37,16 +37,21 @@ UNIFIED_SOURCES += [
     'RefCountedCopyConstructorChecker.cpp',
     'RefCountedInsideLambdaChecker.cpp',
     'ScopeChecker.cpp',
     'SprintfLiteralChecker.cpp',
     'TrivialCtorDtorChecker.cpp',
     'VariableUsageHelpers.cpp',
 ]
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    UNIFIED_SOURCES += [
+        'LoadLibraryUsageChecker.cpp',
+    ]
+
 if CONFIG['ENABLE_MOZSEARCH_PLUGIN']:
     UNIFIED_SOURCES += [
         'mozsearch-plugin/FileOperations.cpp',
         'mozsearch-plugin/JSONFormatter.cpp',
         'mozsearch-plugin/MozsearchIndexer.cpp',
         'mozsearch-plugin/StringOperations.cpp',
     ]
 
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestLoadLibraryUsage.cpp
@@ -0,0 +1,20 @@
+#include <windows.h>
+#include "prlink.h"
+
+void Func() {
+  auto h1 = PR_LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as PR_LoadLibrary) is forbidden.}}
+  auto h2 = PR_LoadLibrary("C:\\Some\\Path");
+  auto h3 = LoadLibraryA(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}}
+  auto h4 = LoadLibraryA("C:\\Some\\Path");
+  auto h5 = LoadLibraryExA(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}}
+  auto h6 = LoadLibraryExA("C:\\Some\\Path", nullptr, 0);
+
+#ifndef UNICODE
+  // LoadLibrary is a defnine for LoadLibraryA
+  auto h7 = LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}}
+  auto h8 = LoadLibrary("C:\\Some\\Path");
+  // LoadLibraryEx is a define for LoadLibraryExA
+  auto h9 = LoadLibraryEx(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}}
+  auto h10 = LoadLibraryEx("C:\\Some\\Path", nullptr, 0);
+#endif
+}
\ No newline at end of file
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -42,16 +42,21 @@ SOURCES += [
     'TestParamTraitsEnum.cpp',
     'TestRefCountedCopyConstructor.cpp',
     'TestSprintfLiteral.cpp',
     'TestStackClass.cpp',
     'TestTemporaryClass.cpp',
     'TestTrivialCtorDtor.cpp',
 ]
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    SOURCES += [
+        'TestLoadLibraryUsage.cpp',
+    ]
+
 DisableStlWrapping()
 NoVisibilityFlags()
 
 # Build without any warning flags, and with clang verify flag for a
 # syntax-only build (no codegen), without a limit on the number of errors.
 COMPILE_FLAGS['OS_CXXFLAGS'] = (
     [f for f in COMPILE_FLAGS.get('OS_CXXFLAGS', []) if not f.startswith('-W')] +
     ['-fsyntax-only', '-Xclang', '-verify', '-ferror-limit=0', '-Wno-invalid-noreturn']
--- a/tools/rewriting/ThirdPartyPaths.txt
+++ b/tools/rewriting/ThirdPartyPaths.txt
@@ -19,24 +19,17 @@ gfx/wrench/
 gfx/ycbcr/
 intl/hyphenation/hyphen/
 intl/icu/
 ipc/chromium/
 js/src/ctypes/libffi/
 js/src/dtoa.c
 js/src/jit/arm64/vixl/
 js/src/vtune/disable_warnings.h
-js/src/vtune/ittnotify.h
-js/src/vtune/ittnotify_config.h
-js/src/vtune/ittnotify_static.c
-js/src/vtune/ittnotify_static.h
-js/src/vtune/ittnotify_types.h
-js/src/vtune/jitprofiling.c
-js/src/vtune/jitprofiling.h
-js/src/vtune/legacy/
+js/src/vtune/
 media/ffvpx/
 media/gmp-clearkey/0.1/openaes/
 media/kiss_fft/
 media/libav/
 media/libcubeb/
 media/libjpeg/
 media/libmkv/
 media/libnestegg/