Skip to content

[Macros] Recovery after executable plugin crash #64555

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

Merged
merged 1 commit into from
Mar 24, 2023

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented Mar 23, 2023

When executable plugins crashed or somehow decided to exit, the compiler
should relaunch the plugin executable before sending another message.

  • LoadedExecutablePlugin is now a process manager of the plugin executable.
  • LoadedExecutabePlugin::PluginProcess represents the actual plugin process
  • LoadedExecutablePlugin::spawnIfNeeded()

@rintaro
Copy link
Member Author

rintaro commented Mar 23, 2023

@swift-ci Please smoke test

@rintaro rintaro force-pushed the macros-plugins-crashrecover branch from 114e373 to c2d27b2 Compare March 23, 2023 04:29
@rintaro
Copy link
Member Author

rintaro commented Mar 23, 2023

@swift-ci Please smoke test

@rintaro rintaro force-pushed the macros-plugins-crashrecover branch from c2d27b2 to 7de1669 Compare March 23, 2023 05:16
@rintaro
Copy link
Member Author

rintaro commented Mar 23, 2023

@swift-ci Please smoke test

@rintaro rintaro changed the title [Macros] Recovery after exectuable plugin crash [Macros] Recovery after executable plugin crash Mar 23, 2023
@rintaro rintaro force-pushed the macros-plugins-crashrecover branch from 7de1669 to ade92be Compare March 23, 2023 19:47
@rintaro
Copy link
Member Author

rintaro commented Mar 23, 2023

@swift-ci Please smoke test

@@ -38,9 +38,6 @@
#include <io.h>
#endif

extern "C" const void *swift_ASTGen_getCompilerPluginCapability(void *handle);
extern "C" void swift_ASTGen_destroyCompilerPluginCapability(void *value);
Copy link
Member Author

Choose a reason for hiding this comment

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

These were unused declarations accidentally added in 0e31393

@rintaro rintaro requested a review from bnbarham March 23, 2023 22:44
Comment on lines 342 to 350
executablePlugin, resolvedLibraryPath.c_str(), moduleName.str().data(),
executablePlugin, resolvedLibraryPathStr.data(), moduleNameStr.data(),
Copy link
Member Author

Choose a reason for hiding this comment

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

s/data()/c_str()/g. Ditto for the callback.

void lock() { mtx.lock(); }
void unlock() { mtx.unlock(); }

// Launch the plugin if it's not already running, or it's stale. Return an
// error if
Copy link
Contributor

Choose a reason for hiding this comment

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

error if ... isn't finished

@@ -94,8 +91,35 @@ PluginRegistry::loadExecutablePlugin(StringRef path) {
"not executable");
}

plugin = std::unique_ptr<LoadedExecutablePlugin>(
Copy link
Contributor

Choose a reason for hiding this comment

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

You could have this as a local instead and only set it after it's valid (ie. after the spawnIfNeeded). Not crucial, but nice to have it not set unless it's valid IMO.

@@ -179,6 +211,7 @@ ssize_t LoadedExecutablePlugin::write(const void *buf, size_t nbyte) const {
}

llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) const {
assert(isAlive());
Copy link
Contributor

Choose a reason for hiding this comment

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

Someone could theoretically kill the process between where we spawn and sendMessage. It's handled below (ie. write would fail), so I'd probably just remove this.

let s1: String = #stringify(a + b).1
print(s1)

let s2: String = #evil(42) // expected-error {{failedToReceiveMessage (from macro 'evil')}}
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably change this message + write out a reproducer for the failure on read. On write... I'm not really sure what to add 😅. Not for this PR though


// Remove the callback and deallocate it when this ASTContext is destructed.
ctx.addCleanup([executablePlugin, callback]() {
executablePlugin->removeOnReconnect(callback);
Copy link
Member Author

@rintaro rintaro Mar 24, 2023

Choose a reason for hiding this comment

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

This is not safe when the PluginRegistry is owned by ASTContext. Currently when ASTContext is to own a PluginRegistry, it adds a cleanup function like this->addCleanup([registry]{ delete registry; }), and cleanup functions are called in the order they are added. That means that the plugin registry and its plugins would be deleted before this callback is called. To resolve this:

  • Instead of using cleanup callback for the plugin registry, add a fieldstd::unique_ptr<PluginRegistry> OwnedPluginRegistry to ASTContext::Implementation so it'd be alive until these callbacks are called
  • or, call ASTContext cleanup callbacks in reverse order, like a stack

@bnbarham wdyt?

Copy link
Member Author

@rintaro rintaro Mar 24, 2023

Choose a reason for hiding this comment

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

Went with the former because I think we should reduce the use of addCleanup whenever possible.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good to me. I'm all for more managed pointers :). IMO the latter also makes sense as a general change.

When executable plugins crashed or somehow decided to exit, the compiler
should relaunch the plugin executable before sending another message.
@rintaro rintaro force-pushed the macros-plugins-crashrecover branch from ade92be to a49ab25 Compare March 24, 2023 05:27
@rintaro
Copy link
Member Author

rintaro commented Mar 24, 2023

@swift-ci Please smoke test

@rintaro rintaro merged commit 2a7f985 into swiftlang:main Mar 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants