-
Notifications
You must be signed in to change notification settings - Fork 405
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
Get rid of UB when copying to and from empty unmanaged views #1968
Conversation
For the record View<int*, MemoryTraits<Unmanaged>> v1( nullptr, 0 );
View<int*, MemoryTraits<Unmanaged>> v2( reinterpret_cast<int*>(-1), 0 );
View<int*> v3("v3", 0);
View<int*> v4("v4", 10);
#ifdef KOKKOS_ENABLE_DEPRECATED_CODE
deep_copy(v1, v2); // fixed
deep_copy(v2, v1); // fixed
deep_copy(v1, v3); // ok
deep_copy(v3, v1); // ok
deep_copy(v2, v3); // fixed
deep_copy(v3, v2); // fixed
ASSERT_NO_THROW( deep_copy(v1, v4) );
ASSERT_NO_THROW( deep_copy(v4, v1) );
ASSERT_NO_THROW( deep_copy(v2, v4) );
ASSERT_NO_THROW( deep_copy(v4, v2) );
ASSERT_NO_THROW( deep_copy(v3, v4) );
ASSERT_NO_THROW( deep_copy(v4, v3) );
#else
deep_copy(v1, v2); // fixed
deep_copy(v2, v1); // fixed
deep_copy(v1, v3); // fixed
deep_copy(v3, v1); // fixed
deep_copy(v2, v3); // ok
deep_copy(v3, v2); // ok
using DimensionMismatchError = std::runtime_error;
ASSERT_THROW( deep_copy(v1, v4), DimensionMismatchError );
ASSERT_THROW( deep_copy(v4, v1), DimensionMismatchError );
ASSERT_THROW( deep_copy(v2, v4), DimensionMismatchError );
ASSERT_THROW( deep_copy(v4, v2), DimensionMismatchError );
ASSERT_THROW( deep_copy(v3, v4), DimensionMismatchError );
ASSERT_THROW( deep_copy(v4, v3), DimensionMismatchError );
#endif |
#define ASSERT_NO_THROW(expression) { \
try { \
expression; \
} \
catch (...) { \
std::cerr<<__FILE__<<":"<<__LINE__<<" "<<#expression<<" did throw an error\n"; \
std::abort(); \
} \
}
#define ASSERT_THROW(expression, exception_type) { \
try { \
expression; \
std::cerr<<__FILE__<<":"<<__LINE__<<" "<<#expression<<" did not throw "<<#exception_type<<"\n"; \
std::abort(); \
} \
catch (exception_type const &) { \
/*success*/ \
} \
catch (...) { \
std::cerr<<__FILE__<<":"<<__LINE__<<" "<<#expression<<" did throw but exception type was not "<<#exception_type<<"\n"; \
std::abort(); \
} \
} |
This is ok. We need to run the spot-check, then get it in. |
(src.extent(7) != dst.extent(7)) | ||
) { | ||
std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); | ||
message += dst.label(); message += "("; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could see this "print all the extents" feature being useful elsewhere. In a future refactor, consider making this a separate function.
@@ -1401,7 +1401,33 @@ void deep_copy | |||
typedef typename src_type::memory_space src_memory_space ; | |||
typedef typename dst_type::value_type dst_value_type ; | |||
typedef typename src_type::value_type src_value_type ; | |||
if(dst.data() == NULL && src.data() == NULL) { | |||
if(dst.data() == NULL || src.data() == NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A question not relevant to this fix: Why can't this specialization of deep_copy
just call the one that takes an execution space instance as its first argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point Mark. I just went over the source code and I believe calling the other one with the execution space of the destination would do the trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would remove ~200 lines of essentially duplicated code. I am trying it locally, building the tests at the moment. Haven't looked into the other 3 pairs of deep_copy(dst, src)
and deep_copy(exec_space, dst, src)
in details to see if there was more opportunity to downsize the amount of code to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could have a merge conflict with #1919 , but in general is in the spirit of making Kokkos respect execution space instances throughout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mhoemmen Some tests were failing now. It is not obvious to me what went wrong, whether I overlooked some subtle difference between the two functions (most likely the issue...) or if I messed up when I implemented the changes you suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dalg24 I remember trying this once before and having the same issue. Thanks for trying, though! It's fine to duplicate that code for now.
We also need to add a unit test which tests the behaviour described in #1967 so it doesn't break again by accident in the future. |
I ran the spot-check on kokkos-dev, all tests pass:
|
Nathan: please post the whole output so it includes the SHA. |
I am not so familiar with you automated testing setup. Do you have any of the builds using Clang sanitizers? That would definitely expose the bug with the code I posted. |
@crtrott Here's the full output
|
Adding UnitTest and rerunning spot-check right now. |
Kokkos::deep_copy(v_m_1, v_um_def_2); | ||
Kokkos::deep_copy(v_m_1, v_um_2); | ||
Kokkos::deep_copy(v_m_1, v_m_def_2); | ||
Kokkos::deep_copy(v_m_1, v_m_2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@crtrott You might want to include the part where I make sure that an exception is thrown if attempting to copy from or to empty views where the other operand is some view with extents that do not match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah not a bad idea. I think we need to make this a part of a larger push to test for asserts where asserts are expected. We have precious little of this right now.
|
Had accidentally amended a commit. But this was now tested. Just waiting for travis to go through than we can merge this in. |
fix #1967
Note I copy/pasted the code that throws if the destination and source views dimension do not match which is not ideal...
Let me know if you want me to change that.