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

muzzle field and method matching #422

Merged
merged 10 commits into from Aug 14, 2018

Conversation

realark
Copy link
Contributor

@realark realark commented Aug 1, 2018

Merging to integration branch.

Add new muzzle checks:

  • Class access flags
  • Methods on class and access flags
  • Fields on class and access flags
  • Fixed a bug in the PatchLogger caught by muzzle.
  • Use a caching type pool strategy to reduce calls to getting classloader resources

With these changes muzzle can now check everything classLoaderHasClasses can check. There's still work to be done to hook up the version scan plugin, update the version ranges, and remove classLoaderHas* checks. That work will go into a later PR against the same integration branch.

@realark realark added comp: core Tracer core tag: do not merge Do not merge changes labels Aug 1, 2018
@realark realark force-pushed the ark/muzzle-fields-and-methods branch from 51cfe37 to c1ec598 Compare August 2, 2018 00:36
@realark realark changed the base branch from ark/muzzle-integration-branch to master August 3, 2018 02:36
@realark realark changed the base branch from master to ark/muzzle-integration-branch August 3, 2018 02:36
@realark realark force-pushed the ark/muzzle-fields-and-methods branch from 17f343f to 4087187 Compare August 3, 2018 03:00
@realark realark removed the tag: do not merge Do not merge changes label Aug 3, 2018
@realark realark requested a review from mar-kolya August 3, 2018 03:03
@realark realark force-pushed the ark/muzzle-fields-and-methods branch 3 times, most recently from 53be9dc to 0cbef2d Compare August 3, 2018 07:49
log.debug(
"Instrumentation muzzled: {} -- {} on {}",
instrumentationPrimaryName,
this.getClass().getName(),
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 this thises would get wiped out by our current IDEA config - but I guess not by gradle formatter

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing for consistency.

} finally {
findLoadedClassMethod.setAccessible(false);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Wasn 't the plan to remove these methods to avoid Java10 problems?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, I brought that back when I resolved a merge conflict. I forgot that we intentionally removed it.

@realark realark force-pushed the ark/muzzle-fields-and-methods branch from 3441638 to 50ed54c Compare August 3, 2018 21:19
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.Type;

/** An immutable reference to a jvm class. */
Copy link
Contributor

Choose a reason for hiding this comment

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

This didn't change in this PR, but this is not really 'immutable' because as far as I can see it uses mutable collections.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reference's immutability is more of a convention than a strict enforcement. I'd like to address this in another "cleanup" PR for easier reviewing.

@@ -79,7 +80,7 @@ public Reference merge(Reference anotherReference) {

return new Reference(
merge(sources, anotherReference.sources),
merge(flags, anotherReference.flags),
mergeFlags(flags, anotherReference.flags),
Copy link
Contributor

Choose a reason for hiding this comment

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

This method has TODO in it, was that TODO meant to be addressed?

Copy link
Contributor

Choose a reason for hiding this comment

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

merge(fields, anotherReference.fields),
merge(methods, anotherReference.methods)

these two lines below simply merge sets. Code in withField and withMethod does 'deep merging'. Is this expected? If so - could you please consider adding comment explaining why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Merging should be a deep merge. Fixing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The TODO in flag merging is an optimization. No need to check for PRIVATE_OR_HIGHER if PUBLIC is already being checked.

@@ -195,111 +175,361 @@ String getMismatchDetails() {
return "Missing class " + className;
}
}

public static class MissingFlag extends Mismatch {
Copy link
Contributor

Choose a reason for hiding this comment

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

It would have been very useful if classes had javadoc describing their meaning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

@@ -195,111 +175,361 @@ String getMismatchDetails() {
return "Missing class " + className;
}
}

public static class MissingFlag extends Mismatch {
final Flag expectedFlag;
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like majority (all?) fields on Mismatches can be made final.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

public ReferenceCheckError(
Exception e, Reference referenceBeingChecked, ClassLoader classLoaderBeingChecked) {
super(new Source[0]);
this.referenceCheckExcetpion = e;
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: Exception

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

@mar-kolya mar-kolya left a comment

Choose a reason for hiding this comment

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

I think this looks very good. I've left a few comments, but some of them are just typos and others are just suggestions to improve design a little bit.


@Override
public boolean matches(int asmFlags) {
return (Opcodes.ACC_PUBLIC & asmFlags) != 0 || (Opcodes.ACC_PROTECTED & asmFlags) != 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of repeating (Opcodes.ACC_PUBLIC & asmFlags) != 0 you could consider using PUBLIC.matches

NON_STATIC,
INTERFACE,
NON_INTERFACE
public enum Flag {
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 overall this whole file is quite large now and covers multiple concerns which makes it harder to read. You may want consider splitting 'helper' classes like this one into a separate package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I'll save that for a cleanup PR.

Source[] sources, Flag[] flags, String name, Type returnType, Type[] parameterTypes) {
this(
new HashSet<>(Arrays.asList(sources)),
new HashSet<>(Arrays.asList(flags)),
Copy link
Contributor

Choose a reason for hiding this comment

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

This implementation makes instances mutable. Is there any reason not to:

  • Use Guava immutable containers
  • Use actual container types (lists) as inputs, not arrays: ImmutableList.of(value1, value1) is quite convenient.

@Override
public String toString() {
// <init>()V
// toString()Ljava/lang/String;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comment meant to be here? If so, I'm not sure I can follow the meaning of it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That should have been removed.

}
}
return true;
return toString().equals(o.toString());
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please add a comment outlining why this is a valid way of comparing these objects?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored the code to make it cleaner.

.withFlag(computeMinimumClassAccess(refSourceType, paramType))
.build());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like some copy-paste is going on here and there might be an opportunity for some helper methods - see comments above.

@@ -56,7 +63,7 @@ public boolean matches(final ClassLoader loader) {
// Don't reference-check helper classes.
// They will be injected by the instrumentation's HelperInjector.
if (!helperClassNames.contains(reference.getClassName())) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is slightly unclear: wouldn't this prevent references of helper classes from being checked as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, just the helper class itself won't be checked. Any reference created by the helper will be checked.

}
}
if (typeOnClasspath.getSuperClass() != null) {
FieldDescription.InDefinedShape fieldOnSupertype =
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't this see private fields on super type as local private fields which is probably wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but then an access mismatch will be raised. I think a mismatched access error is clearer than a missing field error. I'll add a comment explaining that.

return methodOnSupertype;
}
}
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to be to large extent the same logic as findField - which goes back to my previous comment this there might be an opportunity to refactor things so field and method are joined into one 'member' type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That might be best long-term, but for now I don't see much benefit of joining the two types.

}
}
return null
}
Copy link
Contributor

@mar-kolya mar-kolya Aug 6, 2018

Choose a reason for hiding this comment

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

Why are these helpers needed? From the looks of it in current implementation Set's .get should do exactly the same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMO It makes the test code easier to read.

@realark realark dismissed mar-kolya’s stale review August 14, 2018 01:52

Thanks for the review! Cleanup feedback backlogged and other feedback addressed.

merged.set(i, merged.get(i).merge(field));
}
}
return new HashSet<>(merged);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an odd way of merging sets, that also may be slow. Would you consider using something like new HashSet<>(Sets.union(fields2, fields1))?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I see now why this has been done this way, please ignore that comment

@realark realark merged commit 18e713e into ark/muzzle-integration-branch Aug 14, 2018
@realark realark deleted the ark/muzzle-fields-and-methods branch August 14, 2018 18:20
@tylerbenson tylerbenson added this to the 0.13.0 milestone Aug 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: core Tracer core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants