File: module_watcher_win.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (152 lines) | stat: -rw-r--r-- 6,168 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
#define CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_

#include <memory>

#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"

class ModuleWatcherTest;

union LDR_DLL_NOTIFICATION_DATA;

// This class observes modules as they are loaded into a process's address
// space.
//
// This class is safe to be created on any thread. Similarly, it is safe to be
// destroyed on any thread, independent of the thread on which the instance was
// created.
class ModuleWatcher {
 public:
  // The types of module events that can occur.
  enum class ModuleEventType {
    // A module was already loaded, but its presence is being observed.
    kModuleAlreadyLoaded,
    // A module is in the process of being loaded.
    kModuleLoaded,
  };

  // Houses information about a module event, and some module metadata.
  struct ModuleEvent {
    ModuleEvent() = default;
    ModuleEvent(const ModuleEvent& other) = default;
    ModuleEvent(ModuleEventType event_type,
                const base::FilePath& module_path,
                void* module_load_address,
                size_t module_size)
        : event_type(event_type),
          module_path(module_path),
          module_load_address(module_load_address),
          module_size(module_size) {}

    // The type of module event.
    ModuleEventType event_type;
    // The full path to the module on disk.
    base::FilePath module_path;
    // The load address of the module. Careful consideration must be made before
    // accessing memory at this address. See the comment for
    // OnModuleEventCallback.
    raw_ptr<void> module_load_address;
    // The size of the module in memory.
    size_t module_size;
  };

  // The type of callback that will be invoked for each module event. This
  // callback may be run from any thread in the process, and may be invoked
  // during initialization (while iterating over already loaded modules) or in
  // response to LdrDllNotifications received from the loader. As such, keep the
  // amount of work performed here to an absolute minimum.
  //
  // MODULE_LOADED events are always dispatched directly from the loader while
  // under the loader's lock, so the module is guaranteed to be loaded in memory
  // (it is safe to access module_load_address).
  //
  // If the event is of type MODULE_ALREADY_LOADED, then the module data comes
  // from a snapshot and it is possible that its |module_load_address| is
  // invalid by the time the event is sent.
  //
  // Note that it is possible for this callback to be invoked after the
  // destruction of the watcher.
  using OnModuleEventCallback =
      base::RepeatingCallback<void(const ModuleEvent& event)>;

  // Creates and starts a watcher. This enumerates all loaded modules
  // synchronously on the current thread during construction, and provides
  // synchronous notifications as modules are loaded. The callback is invoked in
  // the context of the thread that is loading a module, and as such may be
  // invoked on any thread in the process. Note that it is possible to receive
  // two notifications for some modules as the initial loaded module enumeration
  // races briefly with the callback mechanism. In this case both a
  // MODULE_LOADED and a MODULE_ALREADY_LOADED event will be received for the
  // same module. Since the callback is installed first no modules can be
  // missed, however. This factory function may be called on any thread.
  //
  // Only a single instance of a watcher may exist at any moment. This will
  // return nullptr when trying to create a second watcher.
  static std::unique_ptr<ModuleWatcher> Create(OnModuleEventCallback callback);

  ModuleWatcher(const ModuleWatcher&) = delete;
  ModuleWatcher& operator=(const ModuleWatcher&) = delete;

  // This can be called on any thread. After destruction the |callback|
  // provided to the constructor will no longer be invoked with module events.
  ~ModuleWatcher();

 private:
  // For unittesting.
  friend class ModuleWatcherTest;

  // Private to enforce Singleton semantics. See Create above.
  ModuleWatcher();

  // Initializes the ModuleWatcher instance.
  void Initialize(OnModuleEventCallback callback);

  // Registers a DllNotification callback with the OS. Modifies
  // |dll_notification_cookie_|. Can be called on any thread.
  void RegisterDllNotificationCallback();

  // Removes the installed DllNotification callback. Modifies
  // |dll_notification_cookie_|. Can be called on any thread.
  void UnregisterDllNotificationCallback();

  // Enumerates all currently loaded modules, synchronously invoking callbacks
  // on the current thread. Can be called on any thread.
  static void EnumerateAlreadyLoadedModules(
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      OnModuleEventCallback callback);

  // Helper function for retrieving the callback associated with a given
  // LdrNotification context.
  static OnModuleEventCallback GetCallbackForContext(void* context);

  // The loader notification callback. This is actually
  // void CALLBACK LoaderNotificationCallback(
  //     DWORD, const LDR_DLL_NOTIFICATION_DATA*, PVOID)
  // Not using CALLBACK/DWORD/PVOID allows skipping the windows.h header from
  // this file.
  static void __stdcall LoaderNotificationCallback(
      unsigned long notification_reason,
      const LDR_DLL_NOTIFICATION_DATA* notification_data,
      void* context);

  // Used to bind the |callback_| to a WeakPtr.
  void RunCallback(const ModuleEvent& event);

  // The current callback. Can end up being invoked on any thread.
  OnModuleEventCallback callback_;
  // Used by the DllNotification mechanism.
  raw_ptr<void> dll_notification_cookie_ = nullptr;

  base::WeakPtrFactory<ModuleWatcher> weak_ptr_factory_{this};
};

#endif  // CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_