Skip to content

Conversation

@davisusanibar
Copy link
Contributor

@davisusanibar davisusanibar commented Sep 14, 2023

Rationale for this change

Closes: #37286

What changes are included in this PR?

Initial support for:

  • Use the Checker Framework to enhances Java’s type system to make it more powerful and useful. Planning to start with Nullness Checker

Are these changes tested?

These are the activities involved on this PR:

  • Configure the Checker Framework
  • Treat checker errors as warnings initially
  • Applying Nullness Checker annotation as needed: @nonnull / @nullable
  • Check if building timer increases after this checker is added
  • Fixes for code review

Are there any user-facing changes?

Yes

@github-actions
Copy link

Thanks for opening a pull request!

If this is not a minor PR. Could you open an issue for this pull request on GitHub? https://github.com/apache/arrow/issues/new/choose

Opening GitHub issues ahead of time contributes to the Openness of the Apache Arrow project.

Then could you also rename the pull request title in the following format?

GH-${GITHUB_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}

or

MINOR: [${COMPONENT}] ${SUMMARY}

In the case of PARQUET issues on JIRA the title also supports:

PARQUET-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}

See also:

@davisusanibar davisusanibar changed the title Null ability impl GH-37286: [Java] Start adding nullability/nullness annotations Sep 14, 2023
@github-actions
Copy link

⚠️ GitHub issue #37286 has been automatically assigned in GitHub to PR creator.

@davisusanibar
Copy link
Contributor Author

Hello @lidavidm, could you please provide me with an initial review of how I intend to integrate Nullness evaluation into Java modules (please consider only: arrow-memory-core initially)?

I have these 02 doubts:

  • There are a lots of warning message if we are planning to include Nullness Checker ... then is needed to define an initial scope that could be:
    1. Define what modules need to be analyzed by Nullness Checker, or
    2. Define what classes need to be analyzed by Nullness Checker.
  • The building time of Java modules has doubled since Nullness Checker has been added.

Could you please help me with these two doubts so that I know how to proceed?

Thank you in advance

@lidavidm
Copy link
Member

For (1), what are some examples of the warnings? Ideally, we'd only enable it one module at a time.

For (2), can we enable it only in a separate profile, and have that be run in CI? That way it does not affect the 'normal' builds.

java/pom.xml Outdated
<errorprone.javac.version>9+181-r4173-1</errorprone.javac.version>
<error_prone_core.version>2.16</error_prone_core.version>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<pinjdk8.errorprone.core.version>2.10.0</pinjdk8.errorprone.core.version>
Copy link
Member

Choose a reason for hiding this comment

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

More reason to drop JDK8 ASAP.

java/pom.xml Outdated
with other annotation processors.
See https://github.com/jbosstools/m2e-apt/issues/62 for details
-->
<id>error-prone-checkerframework-jdk8</id>
Copy link
Member

Choose a reason for hiding this comment

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

IMO, we don't bother enabling this for JDK8. In fact, I'd be OK with dropping error-prone for JDK8 as well, and only enabling these checks only on the latest LTS.

// copy length bytes of data from this ArrowBuf starting at
// address addr(index) into the tmp byte array starting at index 0
byte[] tmp = new byte[length];
MemoryUtil.UNSAFE.copyMemory(null, addr(index), tmp, MemoryUtil.BYTE_ARRAY_BASE_OFFSET, length);
Copy link
Member

Choose a reason for hiding this comment

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

nit: is it possible to make the UNSAFE constant private to avoid other problems like this? (We can do that in a separate ticket.)

}

public static boolean isDebug() {
public static @Nullable boolean isDebug() {
Copy link
Member

Choose a reason for hiding this comment

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

This seems wrong: this is a primitive and should never be null.

public static final String DEBUG_ALLOCATOR = "arrow.memory.debug.allocator";
public static final int DEBUG_LOG_LENGTH = 6;
public static final boolean DEBUG;
public static final @Nullable boolean DEBUG;
Copy link
Member

Choose a reason for hiding this comment

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

This also seems wrong.

private final RootAllocator root;
private final Object DEBUG_LOCK = DEBUG ? new Object() : null;

private final @Nullable Object DEBUG_LOCK = DEBUG ? new Object() : null;
Copy link
Member

Choose a reason for hiding this comment

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

IMO, there is no harm in always initializing this.

* we have a new ledger
* associated with this allocator.
*/
@SuppressWarnings({"nullness:locking.nullable", "nullness:argument"})
Copy link
Member

Choose a reason for hiding this comment

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

What are the warnings here?

* @param hasher the hasher used to calculate the hash code.
*/
public ArrowBufPointer(ArrowBuf buf, long offset, long length, ArrowBufHasher hasher) {
@SuppressWarnings("initialization.fields.uninitialized")
Copy link
Member

Choose a reason for hiding this comment

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

Can we initialize fields instead of suppressing the warnings?

private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MemoryUtil.class);

private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
private static final @Nullable Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
Copy link
Member

Choose a reason for hiding this comment

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

Does Checker Framework have anything for static initializers?

Copy link
Member

Choose a reason for hiding this comment

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

@github-actions github-actions bot added awaiting changes Awaiting changes and removed awaiting review Awaiting review labels Sep 19, 2023
@davisusanibar
Copy link
Contributor Author

For (1), what are some examples of the warnings? Ideally, we'd only enable it one module at a time.

For (2), can we enable it only in a separate profile, and have that be run in CI? That way it does not affect the 'normal' builds.

(1) You could see warning messages here, search for [WARNING] /arrow/java/ inside of {2_AMD64 Debian 9 Java JDK 11 Maven 3.6.2.txt, ...}

(2) Ok, let me add that inside a custom profile only for CI

@lidavidm
Copy link
Member

(1) let's only run the checker on memory-core to start with

@lidavidm
Copy link
Member

For https://github.com/apache/arrow/tree/main/java/format/src/main/java/org/apache/arrow/flatbuf

let's add a package-info.java with a @DefaultQualifiers annotation to mark everything in the package as nullable-by-default

@github-actions github-actions bot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Oct 2, 2023
Copy link
Member

@danepitkin danepitkin left a comment

Choose a reason for hiding this comment

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

Thanks for opening up this PR @davisusanibar!

I see there are a lot of Suppressed warnings. Are they truly all needed? (I haven't looked into all of them). I would like to see zero suppressed warnings if possible. Otherwise, the checker doesn't feel as useful.

java/pom.xml Outdated
<errorprone.javac.version>9+181-r4173-1</errorprone.javac.version>
<error_prone_core.version>2.16</error_prone_core.version>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<checker.framework.version>3.38.0</checker.framework.version>
Copy link
Member

Choose a reason for hiding this comment

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

v3.39.0 just released a few days ago, which adds additional support for Java 21 compilation

Copy link
Member

Choose a reason for hiding this comment

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

Should we try v3.39.0? It might be worth rebasing so that the Java 21 CI job can run to see if its required.

/**
* Constructor. Captures the current stack trace.
*/
@SuppressWarnings("nullness:assignment") //incompatible types in assignment
Copy link
Member

@danepitkin danepitkin Oct 5, 2023

Choose a reason for hiding this comment

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

Can you expand on why this is suppressed? nullness:assignment warning makes me think we can just check the length of the stack trace to make sure we are assigning valid entries.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you expand on why this is suppressed? nullness:assignment warning makes me think we can just check the length of the stack trace to make sure we are assigning valid entries.

It is not necessary, I will update it.

* @return Currently allocate memory in bytes.
*/
public long getAllocatedMemory() {
public long getAllocatedMemory(Accountant this) {
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, is this needed? It's not used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, is this needed? It's not used.

Not needed, I am going to delete that

@davisusanibar
Copy link
Contributor Author

Thanks for opening up this PR @davisusanibar!

I see there are a lot of Suppressed warnings. Are they truly all needed? (I haven't looked into all of them). I would like to see zero suppressed warnings if possible. Otherwise, the checker doesn't feel as useful.

Hi @danepitkin yes this is possible to suppress some warnings such as @SuppressWarnings("nullness:dereference.of.nullable") adding more if/else logic.

Let me add that logic explicitly.

@github-actions github-actions bot added the awaiting change review Awaiting change review label Jan 8, 2024
@davisusanibar davisusanibar requested a review from lidavidm January 8, 2024 18:00
Comment on lines 77 to 79
if (parent == null) {
throw new IllegalArgumentException(String.valueOf("Accountant(parent) must not be null"));
}
Copy link
Member

Choose a reason for hiding this comment

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

Why do you use String.valueOf?

Suggested change
if (parent == null) {
throw new IllegalArgumentException(String.valueOf("Accountant(parent) must not be null"));
}
Preconditions.checkArgument(parent != null, "parent must not be null");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I mention at #37723 (comment) (1st option) if I added Preconditions.xxx then that finished also with errors, then, is needed to add inline throw validation.

Finished OK:

final BufferLedger oldLedger = map.remove(allocator);
if (oldLedger == null) {
  throw new IllegalArgumentException(String.valueOf("BufferLedger(oldLedger) must not be null"));
}
BufferAllocator oldAllocator = oldLedger.getAllocator();

Finished with errors:

final BufferLedger oldLedger = map.remove(allocator);
Preconditions.checkArgument(oldLedger != null, "BufferLedger(oldLedger) must not be null");
BufferAllocator oldAllocator = oldLedger.getAllocator();

Error message:
error: [dereference.of.nullable] dereference of possibly-null reference oldLedger

Copy link
Member

Choose a reason for hiding this comment

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

You need to annotate the Preconditions methods so that Checker Framework recognizes them...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

// there are not supposed to be any references through other allocators. In practice, this doesn't do anything
// as the implementation just forces ownership to be transferred to one of the other extant references.
private volatile BufferLedger owningLedger;
private volatile @Nullable BufferLedger owningLedger;
Copy link
Member

Choose a reason for hiding this comment

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

@davisusanibar can you review this?

private final @Nullable HistoricalLog historicalLog;
private final RoundingPolicy roundingPolicy;
private final AllocationManager.Factory allocationManagerFactory;
private final AllocationManager.@NonNull Factory allocationManagerFactory;
Copy link
Member

Choose a reason for hiding this comment

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

@davisusanibar can you follow up here? File an issue?

* @param eval The assertion to be evaluated at compile time
*/
@AssertMethod
public static void assertMethod(boolean eval) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't see any change.

@github-actions github-actions bot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Jan 8, 2024
@github-actions github-actions bot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Jan 8, 2024
@github-actions github-actions bot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Jan 8, 2024
@davisusanibar davisusanibar requested a review from lidavidm January 8, 2024 20:45
@lidavidm
Copy link
Member

lidavidm commented Jan 8, 2024

@github-actions crossbow submit java

@github-actions github-actions bot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Jan 8, 2024
@github-actions
Copy link

github-actions bot commented Jan 8, 2024

Revision: f92f376

Submitted crossbow builds: ursacomputing/crossbow @ actions-b35c84940e

Task Status
java-jars GitHub Actions
verify-rc-source-java-linux-almalinux-8-amd64 GitHub Actions
verify-rc-source-java-linux-conda-latest-amd64 GitHub Actions
verify-rc-source-java-linux-ubuntu-20.04-amd64 GitHub Actions
verify-rc-source-java-linux-ubuntu-22.04-amd64 GitHub Actions
verify-rc-source-java-macos-amd64 GitHub Actions

@lidavidm lidavidm merged commit ccc79e9 into apache:main Jan 9, 2024
@lidavidm lidavidm removed the awaiting merge Awaiting merge label Jan 9, 2024
@conbench-apache-arrow
Copy link

After merging your PR, Conbench analyzed the 5 benchmarking runs that have been run so far on merge-commit ccc79e9.

There were no benchmark performance regressions. 🎉

The full Conbench report has more details. It also includes information about 3 possible false positives for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…pache#37723)

### Rationale for this change

Closes: apache#37286

### What changes are included in this PR?

Initial support for: 

- Use the Checker Framework to enhances Java’s type system to make it more powerful and useful. Planning to start with [Nullness Checker](https://checkerframework.org/manual/#nullness-checker)

### Are these changes tested?

These are the activities involved on this PR:

- [x] Configure the Checker Framework
- [x] Treat checker errors as warnings initially 
- [x] Applying Nullness Checker annotation as needed: @ NonNull / @ Nullable
- [x] Check if building timer increases after this checker is added
- [x] Fixes for code review

### Are there any user-facing changes?

Yes
* Closes: apache#37286

Lead-authored-by: david dali susanibar arce <[email protected]>
Co-authored-by: David Susanibar Arce <[email protected]>
Co-authored-by: David Susanibar Arce <[email protected]>
Signed-off-by: David Li <[email protected]>
pribor pushed a commit to GlobalWebIndex/arrow that referenced this pull request Oct 24, 2025
…pache#37723)

### Rationale for this change

Closes: apache#37286

### What changes are included in this PR?

Initial support for: 

- Use the Checker Framework to enhances Java’s type system to make it more powerful and useful. Planning to start with [Nullness Checker](https://checkerframework.org/manual/#nullness-checker)

### Are these changes tested?

These are the activities involved on this PR:

- [x] Configure the Checker Framework
- [x] Treat checker errors as warnings initially 
- [x] Applying Nullness Checker annotation as needed: @ NonNull / @ Nullable
- [x] Check if building timer increases after this checker is added
- [x] Fixes for code review

### Are there any user-facing changes?

Yes
* Closes: apache#37286

Lead-authored-by: david dali susanibar arce <[email protected]>
Co-authored-by: David Susanibar Arce <[email protected]>
Co-authored-by: David Susanibar Arce <[email protected]>
Signed-off-by: David Li <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Java] Start adding JSpecify nullability/nullness annotations

4 participants