Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a mechanism for on-demand logging about where a process is loading its code and resources from #3276

Merged
merged 1 commit into from Aug 16, 2022

Conversation

davidquesada
Copy link
Contributor

@davidquesada davidquesada commented Aug 12, 2022

abe18ff

Add a mechanism for on-demand logging about where a process is loading its code and resources from
https://bugs.webkit.org/show_bug.cgi?id=243458
rdar://91325510

Reviewed by Saam Barati.

In order to verify with certainty that WebKit clients are using all the correct content (i.e.
loading code from the correct framework bundles or DYLD shared cache, and loading resources
from the correct paths), it can be useful for a process to self-report all these details so
that automated tests (or manual visual inspection) can validate the coherency of the WebKit
stack (as well as any other application frameworks that may need to be loaded from a variety
of potential locations).

To support this, introduce a means by which clients of the WebKit stack (or more precisely,
users of WTF via JavaScriptCore) can automatically log this information on demand. Upon
initialization of WTF, processes will observe a distributed notification. Upon receiving this
notification, the process will introspect the DYLD shared cache, a specified set of dynamic
libraries, and a specified set of bundles. Information about those items will then be printed
to a dedicated OS log channel as a series of JSON outout that external tooling can parse for
consumption by humans or further tooling.

* Source/WTF/WTF.xcodeproj/project.pbxproj:
    Add references to LibraryPathDiagnostics.{h,mm} and CFPrivSPI.h.
* Source/WTF/wtf/PlatformHave.h:
    Add a few conditional flags for SPI used to gather info to be logged.
* Source/WTF/wtf/Threading.cpp:
(WTF::initialize):
    Initialize the new "library path diagnostics" system when setting up WTF.
* Source/WTF/wtf/darwin/LibraryPathDiagnostics.h: Added.
* Source/WTF/wtf/darwin/LibraryPathDiagnostics.mm: Added.
(WTF::LibraryPathDiagnosticsLogger::LibraryPathDiagnosticsLogger):
(WTF::LibraryPathDiagnosticsLogger::logJSONPayload):
    Logs an individual piece of information by writing the stringification of a JSON payload
    to the associated OS log channel. Examples of payloads could be the UUID/path of the
    process's DYLD shared cache, or the location and version of one loaded bundle with a
    given bundle identifier. The overall compilation of information produced by this logger
    is divided and delivered as multiple JSON payloads because the OS log places a limit on
    the size of a message at 1024 bytes -- a limit that could easily be exceeded if a process
    were to just log the UUIDs and full dylib / bundle paths of every library in the WebKit
    stack. Tooling that wishes to analyze this information must merge all the individual JSON
    payloads read from the system log in order to assemble the complete understanding of a
    process's dynamic library stack.
(WTF::LibraryPathDiagnosticsLogger::logString):
    Emits a string to the log, at a given "path" of nested objects, e.g. logging "XYZ" at the
    path "Foo", "Bar", "Baz" would print the JSON payload `{"Foo":{"Bar":{"Baz":"XYZ"}}}`.
(WTF::LibraryPathDiagnosticsLogger::logObject):
    Ditto, but prints an object at a specified path.
(WTF::LibraryPathDiagnosticsLogger::logError):
    Writes the specified string to the OS log as an error.
(WTF::LibraryPathDiagnosticsLogger::logExecutablePath):
    Logs the current executable's path, after canonicalizing it by resolving all symlinks.
(WTF::LibraryPathDiagnosticsLogger::logDYLDSharedCacheInfo):
    Logs the UUID and path on disk of the process's active DYLD shared cache.
(WTF::isAddressInSharedRegion):
(WTF::LibraryPathDiagnosticsLogger::logDynamicLibraryInfo):
    Logs information about a particular dynamic library, specified by the install name. Using
    `dlopen()` to grab a handle to the library (only if it's already loaded), read the UUID,
    the path "on disk" to the library, and determine whether or not the library (referred to
    by its mach header) is present in the shared cache.
(WTF::LibraryPathDiagnosticsLogger::logBundleInfo):
    Logs information about a particular (Core)Foundation bundle, specified by bundle identifier.
    Look up the bundle and log its version and path on disk (after resolving all symlinks).
(WTF::LibraryPathDiagnosticsLogger::logCryptexCanaryInfo):
    Use chirp to look up canary info for the OS and App cryptexes.
(WTF::LibraryPathDiagnosticsLogger::log):
    Invoke each of the respective methods to log the various categories of information.
(WTF::initializeLibraryPathDiagnostics):
    Register for the distributed notification that triggers the process to log its library info.
(WTF::logLibraryPathDiagnostics):
* Source/WTF/wtf/spi/cf/CFPrivSPI.h: Added.
* Source/WTF/wtf/spi/darwin/dyldSPI.h:

Canonical link: https://commits.webkit.org/253455@main

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Aug 12, 2022
auto payload = JSON::Object::create();
auto iter = path.rbegin();
payload->setString(*iter, string);
for (iter++; iter != path.rend(); iter++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use modern for (:) iteration here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, you're using the iterator once before the loop. This is a nit, but I probably would've used an indexed loop instead of this.

auto payload = JSON::Object::create();
auto iter = path.rbegin();
payload->setObject(*iter, object);
for (iter++; iter != path.rend(); iter++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use modern for (:) iteration here?

{
auto payload = JSON::Object::create();
auto iter = path.rbegin();
payload->setObject(*iter, object);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use WTFMove(object) here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which also makes it less weird to take an rvalue ref but not move it.

Copy link
Contributor

@saambarati saambarati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me

#if HAVE(SHARED_REGION_SPI)
static bool isAddressInSharedRegion(const void* addr)
{
return (uintptr_t)addr >= SHARED_REGION_BASE && (uintptr_t)addr < (SHARED_REGION_BASE + SHARED_REGION_SIZE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's use static_cast or bitwise_cast

@davidquesada davidquesada added merge-queue Applied to send a pull request to merge-queue and removed merging-blocked Applied to prevent a change from being merged labels Aug 15, 2022
…g its code and resources from

https://bugs.webkit.org/show_bug.cgi?id=243458
rdar://91325510

Reviewed by Saam Barati.

In order to verify with certainty that WebKit clients are using all the correct content (i.e.
loading code from the correct framework bundles or DYLD shared cache, and loading resources
from the correct paths), it can be useful for a process to self-report all these details so
that automated tests (or manual visual inspection) can validate the coherency of the WebKit
stack (as well as any other application frameworks that may need to be loaded from a variety
of potential locations).

To support this, introduce a means by which clients of the WebKit stack (or more precisely,
users of WTF via JavaScriptCore) can automatically log this information on demand. Upon
initialization of WTF, processes will observe a distributed notification. Upon receiving this
notification, the process will introspect the DYLD shared cache, a specified set of dynamic
libraries, and a specified set of bundles. Information about those items will then be printed
to a dedicated OS log channel as a series of JSON outout that external tooling can parse for
consumption by humans or further tooling.

* Source/WTF/WTF.xcodeproj/project.pbxproj:
    Add references to LibraryPathDiagnostics.{h,mm} and CFPrivSPI.h.
* Source/WTF/wtf/PlatformHave.h:
    Add a few conditional flags for SPI used to gather info to be logged.
* Source/WTF/wtf/Threading.cpp:
(WTF::initialize):
    Initialize the new "library path diagnostics" system when setting up WTF.
* Source/WTF/wtf/darwin/LibraryPathDiagnostics.h: Added.
* Source/WTF/wtf/darwin/LibraryPathDiagnostics.mm: Added.
(WTF::LibraryPathDiagnosticsLogger::LibraryPathDiagnosticsLogger):
(WTF::LibraryPathDiagnosticsLogger::logJSONPayload):
    Logs an individual piece of information by writing the stringification of a JSON payload
    to the associated OS log channel. Examples of payloads could be the UUID/path of the
    process's DYLD shared cache, or the location and version of one loaded bundle with a
    given bundle identifier. The overall compilation of information produced by this logger
    is divided and delivered as multiple JSON payloads because the OS log places a limit on
    the size of a message at 1024 bytes -- a limit that could easily be exceeded if a process
    were to just log the UUIDs and full dylib / bundle paths of every library in the WebKit
    stack. Tooling that wishes to analyze this information must merge all the individual JSON
    payloads read from the system log in order to assemble the complete understanding of a
    process's dynamic library stack.
(WTF::LibraryPathDiagnosticsLogger::logString):
    Emits a string to the log, at a given "path" of nested objects, e.g. logging "XYZ" at the
    path "Foo", "Bar", "Baz" would print the JSON payload `{"Foo":{"Bar":{"Baz":"XYZ"}}}`.
(WTF::LibraryPathDiagnosticsLogger::logObject):
    Ditto, but prints an object at a specified path.
(WTF::LibraryPathDiagnosticsLogger::logError):
    Writes the specified string to the OS log as an error.
(WTF::LibraryPathDiagnosticsLogger::logExecutablePath):
    Logs the current executable's path, after canonicalizing it by resolving all symlinks.
(WTF::LibraryPathDiagnosticsLogger::logDYLDSharedCacheInfo):
    Logs the UUID and path on disk of the process's active DYLD shared cache.
(WTF::isAddressInSharedRegion):
(WTF::LibraryPathDiagnosticsLogger::logDynamicLibraryInfo):
    Logs information about a particular dynamic library, specified by the install name. Using
    `dlopen()` to grab a handle to the library (only if it's already loaded), read the UUID,
    the path "on disk" to the library, and determine whether or not the library (referred to
    by its mach header) is present in the shared cache.
(WTF::LibraryPathDiagnosticsLogger::logBundleInfo):
    Logs information about a particular (Core)Foundation bundle, specified by bundle identifier.
    Look up the bundle and log its version and path on disk (after resolving all symlinks).
(WTF::LibraryPathDiagnosticsLogger::logCryptexCanaryInfo):
    Use chirp to look up canary info for the OS and App cryptexes.
(WTF::LibraryPathDiagnosticsLogger::log):
    Invoke each of the respective methods to log the various categories of information.
(WTF::initializeLibraryPathDiagnostics):
    Register for the distributed notification that triggers the process to log its library info.
(WTF::logLibraryPathDiagnostics):
* Source/WTF/wtf/spi/cf/CFPrivSPI.h: Added.
* Source/WTF/wtf/spi/darwin/dyldSPI.h:

Canonical link: https://commits.webkit.org/253455@main
@webkit-commit-queue
Copy link
Collaborator

Committed 253455@main (abe18ff): https://commits.webkit.org/253455@main

Reviewed commits have been landed. Closing PR #3276 and removing active labels.

@webkit-early-warning-system webkit-early-warning-system merged commit abe18ff into WebKit:main Aug 16, 2022
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Aug 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants