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

Restrict udiv optimization to case where both are singletons #737

Merged
merged 7 commits into from
Oct 18, 2024

Conversation

Alan-Jowett
Copy link
Contributor

@Alan-Jowett Alan-Jowett commented Oct 16, 2024

Resolves: #736

This pull request includes changes to improve the handling of the modulo operation in the interval analysis and updates to the test cases to ensure correct behavior. The most important changes include modifying the URem method in interval_t to handle singletons more efficiently and adding new test cases to validate the changes.

Improvements to URem method:

  • src/crab/interval.cpp: Modified the interval_t::URem method to handle cases where both the dividend and divisor are singletons more efficiently. This includes handling the case where the divisor is zero.

Updates to test cases:

  • test-data/sdivmod.yaml: Added a new test case for inverted range after modulo operation to ensure the correct handling of signed values.
  • test-data/udivmod.yaml: Added a new test case for inverted range after modulo operation to ensure the correct handling of unsigned values.

Summary by CodeRabbit

  • New Features

    • Enhanced arithmetic operations in the interval_t class for improved type safety and clarity.
    • Introduced a new method for handling dividend adjustments when both operands are non-zero.
    • Added new test cases titled "Inverted range after modulo" for both signed and unsigned division modulo operations.
    • Added a new member function abs() to the number_t class for computing absolute values.
  • Bug Fixes

    • Improved type safety and logic for the URem method in the interval_t class.
    • Aligned post-operation values in the 64-bit modulo test case with the results of the 32-bit modulo test case.

Copy link

coderabbitai bot commented Oct 16, 2024

Walkthrough

The changes in this pull request involve significant modifications to the interval_t class in src/crab/interval.cpp and src/crab/interval.hpp, enhancing arithmetic operations and type safety. A new static method, make_dividend_when_both_nonzero, is introduced, along with updates to multiplication and division operators. Additionally, several test cases are added or modified in test-data/sdivmod.yaml, test-data/udivmod.yaml, and test-data/muldiv.yaml to improve test coverage, particularly for modulo operations under specific conditions.

Changes

File Change Summary
src/crab/interval.cpp Added make_dividend_when_both_nonzero, modified operator*, and refactored operator/ and division methods for improved type safety and clarity.
src/crab/interval.hpp Removed static methods abs, max, and min; updated is_bottom and is_top methods; modified operator* declaration.
test-data/sdivmod.yaml Added a new test case "Inverted range after modulo" with specific preconditions and postconditions.
test-data/udivmod.yaml Added a new test case "Inverted range after modulo" with specific preconditions and postconditions.
test-data/muldiv.yaml Updated post-operation values for 64-bit modulo test cases and added new test cases for negative divisors.
src/crab_utils/num_big.hpp Added a new method abs() to the number_t class for computing absolute values.

Assessment against linked issues

Objective Addressed Explanation
Improve handling of modulo operation to avoid assertion failures (#736)

Possibly related PRs

Suggested reviewers

  • dthaler

Poem

In the meadow where numbers play,
Remainders hop and skip all day.
With new checks in place, oh what a sight,
Zero's no trouble, everything's right!
Test cases added, they dance with glee,
Inverted ranges, as happy as can be! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 80ada1c and ea2278b.

📒 Files selected for processing (3)
  • src/crab/interval.cpp (1 hunks)
  • test-data/sdivmod.yaml (1 hunks)
  • test-data/udivmod.yaml (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/crab/interval.cpp (1)
Learnt from: elazarg
PR: vbpf/ebpf-verifier#687
File: src/crab/interval.hpp:139-140
Timestamp: 2024-09-25T12:27:07.015Z
Learning: In the `UDiv` method, unsigned division is expected to wrap around when handling negative numbers.
🔇 Additional comments (2)
test-data/udivmod.yaml (1)

578-596: Excellent addition of a new test case for inverted range after modulo operation.

This test case is a valuable addition as it covers an important edge case in unsigned modulo operations. It effectively tests the scenario where the input range is inverted (split) by the modulo operation, which can be a tricky situation to handle correctly in interval analysis.

The test case structure is well-defined with clear preconditions, code, and postconditions:

  1. It starts with r0 as any number.
  2. If r0 is less than 0x8000 (32768), it's set to 0.
  3. Otherwise, it undergoes a modulo operation with 0x808 (2056).
  4. The postconditions correctly assert that the final range of r0 is [0, 2055] for both signed and unsigned representations.

This test enhances the robustness of the verifier by ensuring it correctly handles cases where the modulo operation results in a wrapped-around range.

src/crab/interval.cpp (1)

190-197: Improved handling of singleton cases and unsigned operations

The changes in the URem method enhance the handling of unsigned remainder operations for singleton intervals. Here are the key improvements:

  1. The check for both dividend and divisor being singletons is now more explicit, improving readability and maintainability.
  2. Casting both operands to uint64_t ensures that the operation is performed as unsigned, which is correct for URem.
  3. The special case for divisor being zero is now properly handled by returning the dividend, consistent with the behavior in other methods like UDiv.

These changes improve type safety and correctness for unsigned remainder operations, aligning well with the expected behavior of the URem method.

To ensure consistency across the codebase, let's verify if similar improvements have been made in other related methods:

✅ Verification successful

Verification Successful: Consistent Handling Across Related Methods

The updates in the URem method are consistent with implementations in UDiv, SRem, and SDiv methods. This alignment ensures uniform handling of singleton cases and unsigned operations across the interval_t class.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar singleton and unsigned casting patterns in related methods

# Test: Search for similar patterns in UDiv and other related methods
rg --type cpp -A 10 'UDiv|SRem|SDiv' src/crab/interval.cpp

Length of output: 3685

test-data/sdivmod.yaml Outdated Show resolved Hide resolved
Signed-off-by: Alan Jowett <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between ea2278b and 00440a6.

📒 Files selected for processing (2)
  • test-data/sdivmod.yaml (1 hunks)
  • test-data/udivmod.yaml (1 hunks)
🧰 Additional context used
🔇 Additional comments (2)
test-data/udivmod.yaml (2)

578-591: Excellent addition of a new test case for inverted range modulo operation.

This test case is a valuable addition to the test suite. It verifies the correct behavior of the modulo operation on a large inverted unsigned range, which is an important edge case to cover. The test ensures that:

  1. The modulo operation correctly handles large unsigned values.
  2. The result is properly constrained to the expected range [0, 2055].
  3. The signed and unsigned representations of the result are equivalent.

This test case will help maintain the correctness of the modulo operation implementation, especially when dealing with large unsigned ranges.


Line range hint 1-591: Overall, the changes to this file are well-implemented and valuable.

The addition of the "Inverted range after modulo" test case enhances the test suite by covering an important edge case for modulo operations with large unsigned ranges. This test case complements the existing tests and helps ensure the robustness of the modulo operation implementation across a wide range of input values.

test-data/sdivmod.yaml Outdated Show resolved Hide resolved
Alan Jowett added 2 commits October 16, 2024 13:02
Signed-off-by: Alan Jowett <[email protected]>
Signed-off-by: Alan Jowett <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range comments (1)
test-data/muldiv.yaml (1)

Line range hint 1-60: Summary: Test case update improves consistency and correctness

This update to the 64-bit modulo test case with a negative divisor is a valuable improvement to the test suite. It ensures consistency between 32-bit and 64-bit operations and correctly represents the expected behavior of modulo operations with negative divisors. This change contributes to the overall goal of the PR in improving the handling of modulo operations in the interval analysis.

Consider adding more test cases to cover edge cases, such as:

  1. Modulo by 1 and -1
  2. Modulo with the dividend at the limits of the 64-bit range
  3. Modulo with values that are not powers of 2 minus 1

These additional test cases would further strengthen the robustness of the modulo operation handling in the verifier.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 00440a6 and d628b9e.

📒 Files selected for processing (4)
  • src/crab/interval.cpp (1 hunks)
  • test-data/muldiv.yaml (1 hunks)
  • test-data/sdivmod.yaml (1 hunks)
  • test-data/udivmod.yaml (1 hunks)
🧰 Additional context used
📓 Learnings (2)
src/crab/interval.cpp (1)
Learnt from: elazarg
PR: vbpf/ebpf-verifier#687
File: src/crab/interval.hpp:139-140
Timestamp: 2024-09-25T12:27:07.015Z
Learning: In the `UDiv` method, unsigned division is expected to wrap around when handling negative numbers.
test-data/muldiv.yaml (2)
Learnt from: Alan-Jowett
PR: vbpf/ebpf-verifier#731
File: test-data/muldiv.yaml:33-45
Timestamp: 2024-10-15T16:30:42.236Z
Learning: Test cases involving immediate values are designed to test 32-bit scenarios focusing on immediate value cases.
Learnt from: Alan-Jowett
PR: vbpf/ebpf-verifier#731
File: test-data/muldiv.yaml:48-60
Timestamp: 2024-10-15T16:39:16.979Z
Learning: In the eBPF verifier, immediate values are signed 32-bit integers that are sign-extended to 64 bits, and modulo operations on 64-bit values sign-extend the 32-bit signed immediate to a 64-bit signed immediate.
🔇 Additional comments (2)
test-data/muldiv.yaml (1)

59-60: LGTM! The updated values are correct and consistent.

The changes to the 64-bit modulo test case are correct and align with the expected behavior. Here's the verification:

  1. The operation being tested is: 4194435072 % 4096655360
  2. The result 97779712 is correct for both signed and unsigned interpretations.
  3. This is consistent with the 32-bit modulo test case, which uses the same values and produces the same result.

The change addresses the PR objective of improving the handling of modulo operations, particularly for cases where both dividend and divisor are singletons (specific values in this case).

test-data/udivmod.yaml (1)

578-595: Excellent addition of a crucial test case

This new test case, "Inverted range after modulo", is a valuable addition to the test suite. It addresses a specific scenario where the modulo operation results in an inverted range, which previously caused issues in the verifier.

Key points:

  1. The test case uses carefully selected constants (via libfuzzer) to trigger the edge case.
  2. It verifies that the verifier correctly handles the inverted range scenario.
  3. The postconditions accurately reflect the expected outcome of the modulo operation.

This test case directly aligns with the PR objectives and helps prevent regression of the issue described in #736.

test-data/sdivmod.yaml Show resolved Hide resolved
src/crab/interval.cpp Outdated Show resolved Hide resolved
src/crab/interval.cpp Outdated Show resolved Hide resolved
Signed-off-by: Alan Jowett <[email protected]>
@coveralls
Copy link

coveralls commented Oct 16, 2024

Coverage Status

coverage: 90.313% (+0.3%) from 90.0%
when pulling 6902686 on Alan-Jowett:issue736
into 80ada1c on vbpf:main.

src/crab/interval.cpp Outdated Show resolved Hide resolved
* move abs to number_t
* remove interval_t::min and interval_t::max
* move interval::operator* to interval.cpp

Signed-off-by: Elazar Gershuni <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 1c216d4 and 6902686.

📒 Files selected for processing (3)
  • src/crab/interval.cpp (12 hunks)
  • src/crab/interval.hpp (3 hunks)
  • src/crab_utils/num_big.hpp (1 hunks)
🧰 Additional context used
🔇 Additional comments (8)
src/crab/interval.hpp (3)

113-113: LGTM: Simplified is_bottom() method

The removal of parentheses in the is_bottom() method improves readability without changing the logic. This change aligns with modern C++ style guidelines.


118-118: LGTM: Simplified is_top() method

The removal of parentheses in the is_top() method improves readability without changing the logic. This change aligns with modern C++ style guidelines.


222-222: Verify implementation location for operator*

The removal of the inline implementation for operator* is a good practice for separating interface from implementation. This can potentially improve compilation times.

Please ensure that the implementation for this operator is provided in a corresponding .cpp file. Also, verify that this change doesn't negatively impact performance-critical code that might have benefited from the previous inline implementation.

✅ Verification successful

Implementation of operator* found in src/crab/interval.cpp

The implementation of operator* has been successfully moved to the corresponding .cpp file, ensuring separation of interface and implementation. This adheres to best practices and should improve compilation times.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the implementation of operator* in the corresponding .cpp file
rg --type cpp "interval_t interval_t::operator\*\(const interval_t& x\) const" src/

Length of output: 169

src/crab/interval.cpp (5)

40-48: Confirm division by zero handling aligns with eBPF ISA

In the operator/ method, when dividing by zero (c == 0), the code returns interval_t{0} as per the eBPF ISA specifications. This behavior is correct and consistent.


131-135: Validate unsigned division by zero handling

In the UDiv method, when c == 0, the method correctly returns interval_t{0} in accordance with the eBPF ISA. This ensures that unsigned division by zero behaves as expected.


225-231: Ensure URem correctly handles zero in divisor

The method handles cases where the divisor contains zero by splitting the interval. Confirm that this logic is sound and that all edge cases are appropriately managed.

Please add or review unit tests that cover scenarios where the divisor includes zero to ensure correct behavior.


17-28: ⚠️ Potential issue

Ensure correct handling of infinite bounds in multiplication

In the operator* implementation, the multiplication of interval bounds might not handle infinite bounds correctly. Since _lb and _ub can be infinite, multiplying them directly may lead to incorrect results or undefined behavior.

Consider adding checks for infinite bounds and handling them appropriately. For example:

if (_lb.is_infinite() || _ub.is_infinite() || x._lb.is_infinite() || x._ub.is_infinite()) {
    // Handle cases with infinite bounds
    return interval_t{bound_t::minus_infinity(), bound_t::plus_infinity()};
}

Please ensure that unit tests cover cases where intervals have infinite bounds to validate this behavior.


368-370: ⚠️ Potential issue

Handle large shift values in LShr method

In the LShr method, when the shift amount is greater than or equal to the bit width of number_t, the result is defined differently. Ensure that shifts larger than the bit width are correctly handled to prevent incorrect results.

Consider adding a check for the shift amount:

if (*shift >= number_t::bit_width()) {
    return interval_t{0};
}

Add test cases where the shift amount exceeds the bit width to validate this behavior.

src/crab_utils/num_big.hpp Show resolved Hide resolved
src/crab/interval.hpp Show resolved Hide resolved
src/crab/interval.cpp Show resolved Hide resolved
src/crab/interval.cpp Show resolved Hide resolved
src/crab/interval.cpp Show resolved Hide resolved
src/crab/interval.cpp Show resolved Hide resolved
src/crab/interval.cpp Show resolved Hide resolved
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.

Assertion failed: !intv.is_bottom(), file E:\ebpf-verifier\src\crab\split_dbm.cpp, line 953
3 participants