-
Notifications
You must be signed in to change notification settings - Fork 828
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
remove shimmer, implement new one #618
Comments
Bonus: we also remove an external dependency |
Is unpatch really a requirement? It will be really hard to implement a bullet prove patch library which works in all cases. Monkey patching is used more often then someone would expect and there are numerous variants how this is done in detail. There are other reasons why shimmer may be problematic: it has quite some visible side effects like not coping properties to wrapped function or not setting function name/length on wrapped function. Both may break user applications. example:
results in
|
@Flarna |
What properties need to be copied from the original function?
Should it be unpatchable?Is it important that we are actually able to fully unpatch and restore the original version of the function, or is it ok to just have the patched version of the function call the original function if the plugin is disabled? This would reduce the complexity of the shim library, but would require plugins to be aware of their enabled/disabled states. here is an example of what I mean. One example is not unpatchable and relies on the plugin to manage a state. The other is unpatchable and relies on the shim library to restore original functionality. /**
* In this version, the original function is never restored.
* In the case that the plugin is disabled, it just delegates
* execution to the original function at that time
*/
class NotUnpatchAble {
// this property would likely be set by the baseplugin so each plugin
// does not need to implement its own state
private _state = PluginState.UNPATCHED;
patch() {
if (this._state === PluginState.UNPATCHED) {
patch(this._moduleExports, "methodName", this._getPatchedVersion());
}
this._state = PluginState.ENABLED;
}
disable() {
this._state = PluginState.DISABLED
}
private _getPatchedVersion() {
return function (this: any, original: Function) {
if (PluginState.DISABLED) {
return original.apply(this, arguments);
}
// do stuff
}
}
}
/** In this version, the original function is restored */
class UnpatchAble {
patch() {
patch(this._moduleExports, "methodName", this._getPatchedVersion());
}
disable() {
unpatch(this._moduleExports, "methodName");
}
private _getPatchedVersion() {
return function (this: any, original: Function) {
// do stuff
}
}
}
enum PluginState {
UNPATCHED,
DISABLED,
ENABLED,
} |
Is there any use case for un-patching other than disabling a plugin? I can't think of one personally, which leads me to think that that we really need something like a "disable plugin" functionality that could turn off all the plugin specific code besides calling the underlying patched function. I am personally very much in favor of getting rid of shimmer in favor of a ligher weight alternative, because it allows removal of shimmer as a dependency (one less thing that can become vulnerable or incompatible, one less thing customers need to audit for, etc.) |
@draffensperger I was thinking the same thing wrt not unpatching and just delegating. It seems like unpatch is an unnecessarily dangerous step when it comes to multiple wrapping |
And specially, disabling it at runtime which i believe is a really really uncommon thing. Generally people implement a toggle via the environment and disable them by restarting each app, which make the |
In my opinion it's not really possible at all to unpatch everything. If you patch an API like e.g. I think the only valid use case for unpatch is for module tests. |
it's not only about unpatching but patching too. If any other library will use shimmer on the same function it will remove our patch, it will be exactly the same if someone else used shimmer to patch function and then we will patch it - it will remove someone else patch. |
@obecny Totally, that was a issue when i was working at an APM vendor, we couldnt be used at the same time as another. That could be tolerable since generally you don't have multiple APM at the same time. |
this seems to be outdated and unwanted, closing |
Currently the shimmer is a desired way of patching. The problem is that shimmer doesn't support multiple patching. It stores the original into
__original
and that's it. If it happen that someone else will be using this to patch the function we might accidently be unpatched or we might unpatch it too. What if there are multiple libraries that want to patch the same function. It should be possible that all libraries will be able to correctly patch the function and then correctly unpatch it to the state it was, but it should also support the queue to unpatch correctlyFor example
now let say the library from point 2 want to unpatch. The scenario should look like this
So even though the patch has been applied the unpatch should not restore to original, but should be aware of other patches and simply remove the patch it added from the queue.
This way all the libraries that are patching and unpatching will never break each other and you will be able to patch and unpatch such things many times without problem.
If there is no such library I think we should create a new one.
The text was updated successfully, but these errors were encountered: