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

Fix ASAN failures. #345

Merged
merged 1 commit into from
Aug 22, 2024
Merged

Fix ASAN failures. #345

merged 1 commit into from
Aug 22, 2024

Conversation

shaunrd0
Copy link
Contributor

This fixes ASAN failures seen on CI, it looks like they were due to missing calls to Free() either in the example code or internal definitions.

If this looks correct I can follow up and look for similar errors. At the moment this only fixes those reported by build_with_sanitizer_and_run.sh so ASAN CI should pass now, but I would expect there's other similar errors that are not covered by the examples.

@@ -123,7 +123,6 @@ jobs:

Linux_Address_Sanitizer:
# Only run this job for releases
if: github.event_name == 'release' && github.event.action == 'published'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just testing with CI on this PR, once I see it's passing I'll revert this so it's only ran for releases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted this, but kept the removal of continue-on-error, there is a full CI run here with passing ASAN jobs

https://github.com/TileDB-Inc/TileDB-Go/actions/runs/10497212377/job/29079527674?pr=345

@thetorpedodog
Copy link
Contributor

For these lint errors, you should be able to switch them out with a call to the slicePtr function:

TileDB-Go/common.go

Lines 21 to 24 in 0b1650f

// slicePtr gives you an unsafe pointer to the start of a slice.
func slicePtr[T any](slc []T) unsafe.Pointer {
return unsafe.Pointer(unsafe.SliceData(slc))
}

Copy link
Contributor

@NullHypothesis NullHypothesis 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 working on this! I'm surprised by how many Free calls were missing.

array.go Outdated
return nil, false, err
}
// Wrapped in a function so `dimension` will be cleaned up with defer each time the function completes.
err = func() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nicely done!

Copy link
Contributor

Choose a reason for hiding this comment

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

one ever-so-minor nit: I recommend making this err := ..., so that the err here is a new variable independent of the one outside the loop.

Copy link
Contributor

@thetorpedodog thetorpedodog 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 working on this! I'm surprised by how many Free calls were missing.

I actually didn’t realize that after accessing, for example, someArray.Schema(), you were able/allowed to free the schema that was returned to you—I thought it belonged to the array. (Reading the code itself makes it clear that you can, but the GC can still handle it for you if you don’t care about freeing things ASAP (which arguably we should inside our own library, just for the sake of being responsible).)

array.go Outdated
return nil, false, err
}
// Wrapped in a function so `dimension` will be cleaned up with defer each time the function completes.
err = func() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

one ever-so-minor nit: I recommend making this err := ..., so that the err here is a new variable independent of the one outside the loop.

}

dataTypeSize := dimType.Size()
err = func() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

here too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

query_test.go Outdated
@@ -2986,8 +2984,7 @@ func TestGetDataBuffer(t *testing.T) {
require.NoError(t, err)
storedDataBuffer, ok := storedBuffer.([]int32)
require.True(t, ok)
require.Equal(t, ((*reflect.SliceHeader)(unsafe.Pointer(&dataBuffer)).Data),
((*reflect.SliceHeader)(unsafe.Pointer(&storedDataBuffer)).Data))
require.Equal(t, uintptr(slicePtr(dataBuffer)), uintptr(slicePtr(storedDataBuffer)))
Copy link
Contributor

Choose a reason for hiding this comment

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

you should be able to remove these uintptr conversions as well, since both of them are now unsafe.Pointers (I think?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -383,7 +383,7 @@ func (v *VFS) Read(fh *VFSfh, offset uint64, nbytes uint64) ([]byte, error) {
// appends data at the end of the file. If the file does not exist,
// it will be created.
func (v *VFS) Write(fh *VFSfh, bytes []byte) error {
cbuffer := C.CBytes(bytes)
cbuffer := slicePtr(bytes)
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like a very, very good change: C.CBytes makes a copy of the []byte it’s given, which meant that every time we were calling someVFS.Write(fh, ourData), we were leaking a copy of our data. Since this is now using slicePtr, we’re giving it the address of our existing []byte and telling core to look in there.

Copy link
Contributor

Choose a reason for hiding this comment

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

…although I think we may also want a defer runtime.KeepAlive(bytes) right after this, because otherwise bytes is never referenced once it enters the C.tiledb_vfs_write call and thus would be eligible for GC as it is in progress.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

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

really nice catch

@shaunrd0 shaunrd0 merged commit 3e72fa5 into master Aug 22, 2024
8 checks passed
@shaunrd0 shaunrd0 deleted the smr/asan-failures branch August 22, 2024 15:13
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.

4 participants