-
Notifications
You must be signed in to change notification settings - Fork 744
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
Compile time checks for class initialization deadlocks #2062
Comments
@cushon, I'm interested in your thoughts on this when you have a moment. |
+1; this feature would have helped with apache/solr#819 (https://issues.apache.org/jira/browse/SOLR-16165). It's worth mentioning @carterkozak's subsequent blog post on the topic. |
@carterkozak sorry for the very slow response here, are you still interested in contributing this? |
No worries, @cushon. I'd be happy to :-) |
Great, thanks! |
I assume that for AutoValue, and assuming that the generated subclass only gets referenced after static initialization of the parent class has started (i.e. all references to "new AutoValue_Xxx(...)" occur inside the parent class), that this is not an issue? |
@hagbard I think it would be theoretically possible to create deadlocks that involved I guess we might have to be careful about stuff like class Base {
static final Object DEFAULT = new AutoValue_Base();
} @carterkozak I'd still be happy to review a PR for this if you have time and interest :) |
We already have @AutoValue
abstract class Base {
abstract String bar();
static final Object DEFAULT = new AutoValue_Base("bar");
static Base of(String bar) {
return new AutoValue_Base(bar);
}
} If those are the only references to The text below gives more detail, but isn't all that relevant to the issue here, so take it as a footnote. We've encountered a couple of cases at Google where people have used AutoValue with builders in a way that could lead to deadlock. I'm copying some excerpts from our internal issue-tracking system: @AutoValue
public abstract class Foo {
public static final Foo DEFAULT = Builder.builder().build();
@AutoValue.Builder
public abstract static class Builder {
public static Builder builder() {
return new AutoValue_Foo.Builder();
}
public abstract Foo build();
}
} Suppose none of these classes has been initialized, and two threads come along at the same time. Thread A references If the static @AutoValue
public abstract class Foo {
public static final Foo DEFAULT = builder().build();
public static Builder builder() {
return new AutoValue_Foo.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Foo build();
}
} Now A still references AutoValue attempts to detect and warn about this particular pattern but it's still possible to run into it if your code doesn't match exactly what AutoValue is checking for or if you have a hand-written builder. |
@carterkozak any chance this is still on your radar? :) A couple more examples of class initialization deadlocks: |
#2062 PiperOrigin-RevId: 614048707
#2062 PiperOrigin-RevId: 615515920
An initial implementation has been added in 1d99484. Feedback or contributions are very welcome, e.g. if there are ideas about the heuristics or how to make it more precise. |
Circular initialization causes deadlocks for non-interface classes because of the requirement that super classes be initialized first, but that doesn't apply to interfaces, only concrete classes. #2062 PiperOrigin-RevId: 615559458
Circular initialization causes deadlocks for non-interface classes because of the requirement that super classes be initialized first, but that doesn't apply to interfaces, only concrete classes. #2062 PiperOrigin-RevId: 615642376
…or non-static inner classes #2062 PiperOrigin-RevId: 615834242
…or non-static inner classes #2062 PiperOrigin-RevId: 615879331
#2062 PiperOrigin-RevId: 615963586
#2062 PiperOrigin-RevId: 617293200
…e initialized outside the current compilation unit Consider all classes in the super type hierarchy between the subclass and containing superclass, to catch deadlocks where an intermediate supertype can be instantiated. This also fixes an NPE with an existing check for the direct super type. #2062 PiperOrigin-RevId: 615968917
…e initialized outside the current compilation unit Consider all classes in the super type hierarchy between the subclass and containing superclass, to catch deadlocks where an intermediate supertype can be instantiated. This also fixes an NPE with an existing check for the direct super type. #2062 PiperOrigin-RevId: 615968917
…e initialized outside the current compilation unit Consider all classes in the super type hierarchy between the subclass and containing superclass, to catch deadlocks where an intermediate supertype can be instantiated. This also fixes an NPE with an existing check for the direct super type. #2062 PiperOrigin-RevId: 615968917
…e initialized outside the current compilation unit Consider all classes in the super type hierarchy between the subclass and containing superclass, to catch deadlocks where an intermediate supertype can be instantiated. This also fixes an NPE with an existing check for the direct super type. #2062 PiperOrigin-RevId: 615968917
…e initialized outside the current compilation unit Consider all classes in the super type hierarchy between the subclass and containing superclass, to catch deadlocks where an intermediate supertype can be instantiated. This also fixes an NPE with an existing check for the direct super type. #2062 PiperOrigin-RevId: 617314919
Description of the problem / feature request:
Class initialization deadlocks are common when a type uses one of its subtypes in a static field or block.
Feature requests: what underlying problem are you trying to solve with this feature?
I would like to catch these deadlocks at compile time rather than intermittently at runtime!
I have implemented such a check here, but I believe it would be a good candidate for error-prone upstream:
palantir/gradle-baseline#1598
Bugs: what's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.
Example from guava:
google/guava#1977
What version of Error Prone are you using?
2.4.0
Have you found anything relevant by searching the web?
no
The text was updated successfully, but these errors were encountered: