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

GH-35270: [C++] Use Buffer instead of raw buffer in hash join internals #35347

Merged

Conversation

westonpace
Copy link
Member

@westonpace westonpace commented Apr 26, 2023

Rationale for this change

The current code has two storage buffers in the key map which are allocated with MemoryPool::Allocate which does not use smart pointers. This could have led to a potential memory leak in an OOM scenario where the first allocate fails and it also led to some convoluted code keeping track of the previously allocated size in order to properly call Free.

Furthermore, it seems that this key map could have been getting potentially copied in the swiss join code. While that was probably not happening (since the copy happened before the key map was initialized) it is still an easy recipe for an accidental double-free later on as we maintain the class.

What changes are included in this PR?

Those raw buffers are changed to std::shared_ptr to avoid these issues.

Are these changes tested?

Somewhat, the existing unit tests should ensure we didn't cause a regression. I didn't introduce a regression test to introduce this potential bug because it would be very difficult to do so.

Are there any user-facing changes?

No

@github-actions
Copy link

@github-actions
Copy link

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

@@ -226,12 +228,12 @@ class ARROW_EXPORT SwissTable {
// ---------------------------------------------------
// * Empty bucket has value 0x80. Non-empty bucket has highest bit set to 0.
//
uint8_t* blocks_;
std::shared_ptr<Buffer> blocks_;

// Array of hashes of values inserted into slots.
// Undefined if the corresponding slot is empty.
// There is 64B padding at the end.
Copy link
Member

Choose a reason for hiding this comment

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

Should here still mention padding here? Since Buffer already ensure padding?

Copy link
Member Author

Choose a reason for hiding this comment

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

Buffer ensures that allocations are aligned (and I think, at least 64 bytes) but I don't know if it actually guarantees padding. I think this buffer needs to go 64 bytes past the end regardless of the size which is a slightly different requirement.

Copy link
Member

Choose a reason for hiding this comment

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

Got it, padding and aligned are different, I missed it previously. the patch LGTM

@github-actions github-actions bot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels May 5, 2023
Copy link
Member

@pitrou pitrou left a comment

Choose a reason for hiding this comment

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

+1, nice robustness improvement

@pitrou pitrou merged commit 18c9760 into apache:main May 9, 2023
3 checks passed
@ursabot
Copy link

ursabot commented May 10, 2023

Benchmark runs are scheduled for baseline = b372242 and contender = 18c9760. 18c9760 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️8.57% ⬆️0.23%] test-mac-arm
[Finished ⬇️0.0% ⬆️0.0%] ursa-i9-9960x
[Finished ⬇️1.42% ⬆️0.36%] ursa-thinkcentre-m75q
Buildkite builds:
[Finished] 18c97604 ec2-t3-xlarge-us-east-2
[Finished] 18c97604 test-mac-arm
[Finished] 18c97604 ursa-i9-9960x
[Finished] 18c97604 ursa-thinkcentre-m75q
[Finished] b372242b ec2-t3-xlarge-us-east-2
[Finished] b372242b test-mac-arm
[Finished] b372242b ursa-i9-9960x
[Finished] b372242b ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python, R. Runs only benchmarks with cloud = True
test-mac-arm: Supported benchmark langs: C++, Python, R
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

@ursabot
Copy link

ursabot commented May 10, 2023

['Python', 'R'] benchmarks have high level of regressions.
test-mac-arm

liujiacheng777 pushed a commit to LoongArch-Python/arrow that referenced this pull request May 11, 2023
…nternals (apache#35347)

### Rationale for this change

The current code has two storage buffers in the key map which are allocated with MemoryPool::Allocate which does not use smart pointers.  This could have led to a potential memory leak in an OOM scenario where the first allocate fails and it also led to some convoluted code keeping track of the previously allocated size in order to properly call Free.

Furthermore, it seems that this key map could have been getting potentially copied in the swiss join code.  While that was probably not happening (since the copy happened before the key map was initialized) it is still an easy recipe for an accidental double-free later on as we maintain the class.

### What changes are included in this PR?

Those raw buffers are changed to std::shared_ptr<Buffer> to avoid these issues.

### Are these changes tested?

Somewhat, the existing unit tests should ensure we didn't cause a regression.  I didn't introduce a regression test to introduce this potential bug because it would be very difficult to do so.

### Are there any user-facing changes?

No

* Closes: apache#35270

Authored-by: Weston Pace <weston.pace@gmail.com>
Signed-off-by: Antoine Pitrou <antoine@python.org>
ArgusLi pushed a commit to Bit-Quill/arrow that referenced this pull request May 15, 2023
…nternals (apache#35347)

### Rationale for this change

The current code has two storage buffers in the key map which are allocated with MemoryPool::Allocate which does not use smart pointers.  This could have led to a potential memory leak in an OOM scenario where the first allocate fails and it also led to some convoluted code keeping track of the previously allocated size in order to properly call Free.

Furthermore, it seems that this key map could have been getting potentially copied in the swiss join code.  While that was probably not happening (since the copy happened before the key map was initialized) it is still an easy recipe for an accidental double-free later on as we maintain the class.

### What changes are included in this PR?

Those raw buffers are changed to std::shared_ptr<Buffer> to avoid these issues.

### Are these changes tested?

Somewhat, the existing unit tests should ensure we didn't cause a regression.  I didn't introduce a regression test to introduce this potential bug because it would be very difficult to do so.

### Are there any user-facing changes?

No

* Closes: apache#35270

Authored-by: Weston Pace <weston.pace@gmail.com>
Signed-off-by: Antoine Pitrou <antoine@python.org>
rtpsw pushed a commit to rtpsw/arrow that referenced this pull request May 16, 2023
…nternals (apache#35347)

### Rationale for this change

The current code has two storage buffers in the key map which are allocated with MemoryPool::Allocate which does not use smart pointers.  This could have led to a potential memory leak in an OOM scenario where the first allocate fails and it also led to some convoluted code keeping track of the previously allocated size in order to properly call Free.

Furthermore, it seems that this key map could have been getting potentially copied in the swiss join code.  While that was probably not happening (since the copy happened before the key map was initialized) it is still an easy recipe for an accidental double-free later on as we maintain the class.

### What changes are included in this PR?

Those raw buffers are changed to std::shared_ptr<Buffer> to avoid these issues.

### Are these changes tested?

Somewhat, the existing unit tests should ensure we didn't cause a regression.  I didn't introduce a regression test to introduce this potential bug because it would be very difficult to do so.

### Are there any user-facing changes?

No

* Closes: apache#35270

Authored-by: Weston Pace <weston.pace@gmail.com>
Signed-off-by: Antoine Pitrou <antoine@python.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory leak in SwissTable::grow_double()
4 participants