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/assertion error #182

Merged
merged 3 commits into from Mar 17, 2022
Merged

Conversation

sanjayankur31
Copy link
Contributor

@sanjayankur31 sanjayankur31 commented Mar 9, 2022

Fixes an assertion error thrown when _GLIBCXX_ASSERTIONS is defined, and enables the option by default

With `-Wp,-D_GLIBCXX_ASSERTIONS`, tests fail with an assertion error of
the form:

```
/usr/include/c++/12/bits/stl_vector.h:1122: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](size_type) [with _T
p = float; _Alloc = std::allocator<float>; reference = float&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.
```

The assertion failure happens on line 473 in report_reader.cpp:
```
std::copy(&buffer[gid_start], &buffer[gid_end], &data_ptr[offset]);
```

The problem is that `gid_end` can equal the size of `buffer`, and
`&buffer[gid_end]` triggers the assertion failure in that case.

Diagnosed and fixed suggested by Jerry James in the Fedora package
review:
https://bugzilla.redhat.com/show_bug.cgi?id=2061077#c6
@pramodk pramodk requested a review from matz-e March 9, 2022 08:44
Copy link
Member

@matz-e matz-e left a comment

Choose a reason for hiding this comment

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

Seems sensible from my side, wondering if this will work on all compilers though.

@sanjayankur31
Copy link
Contributor Author

I'm not sure what the corresponding flags for clang are, but I see that the CI builds completed fine so perhaps these extra definitions are simply ignored?

@@ -470,7 +470,7 @@ DataFrame<T> ReportReader<T>::Population::get(const nonstd::optional<Selection>&
data_ptr[offset] = buffer[gid_start];
} else { // Elements report
uint64_t gid_end = range.second - min;
std::copy(&buffer[gid_start], &buffer[gid_end], &data_ptr[offset]);
std::copy(buffer.begin() + gid_start, buffer.begin() + gid_end, &data_ptr[offset]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmmm... Do you mind to clarify why the change, please? I don't mind, but if we do change this, we should also change the code in line 470 and we must verify that the performance of the copies remains the same (e.g., this operation is executed thousands of times in thousands of timesteps, it matters!).

On a side note, perhaps using something like std::next(buffer.begin(), gid_start) as well, but this is irrelevant.

Copy link
Contributor

Choose a reason for hiding this comment

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

Turning on the _GLIBCXX_ASSERTIONS makes doing the subscript on buffer look like &buffer[buffer.size()], which would be an out of bounds error and thus undefined behavior. AFAIK, this is ok in this specific case as long as std::copy doesn't deref the pointer.

The change means we use the std::copy overload that takes iterators, and is "safer", because there is no chance there is an OOB deref, as long as gid_end never is larger than the size of the array.

The ASM will look the same from both of them, I'd expect, at a reasonable optimization level.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks @mgeplf for clarifying. My point was that accessing the array with [] in std::copy might avoid boundary checks or additional code, but if you feel that it should be the same, then no complains at all.

I'd still prefer the use of std::next(buffer.begin(), gid_start) and std::next(buffer.begin(), gid_end) with iterators, although I don't mind leaving the code as it is with the + operator.

Copy link
Contributor

Choose a reason for hiding this comment

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

but if you feel that it should be the same, then no complains at all.

Had a quick look on godbolt to confirm (which I never take as conclusive), but it seems that compiler sees through this:
https://godbolt.org/z/8dez5nEM3

I'd still prefer the use of std::next(buffer.begin(), gid_start)

Ok, I'll make those changes, and another one to remove the pointer usage altogether.

Copy link
Contributor

Choose a reason for hiding this comment

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

I've made the changes; any/all reviews welcome.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All tests pass in my Fedora build with the newest changes 👍

@@ -470,7 +470,7 @@ DataFrame<T> ReportReader<T>::Population::get(const nonstd::optional<Selection>&
data_ptr[offset] = buffer[gid_start];
} else { // Elements report
uint64_t gid_end = range.second - min;
std::copy(&buffer[gid_start], &buffer[gid_end], &data_ptr[offset]);
std::copy(buffer.begin() + gid_start, buffer.begin() + gid_end, &data_ptr[offset]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Turning on the _GLIBCXX_ASSERTIONS makes doing the subscript on buffer look like &buffer[buffer.size()], which would be an out of bounds error and thus undefined behavior. AFAIK, this is ok in this specific case as long as std::copy doesn't deref the pointer.

The change means we use the std::copy overload that takes iterators, and is "safer", because there is no chance there is an OOB deref, as long as gid_end never is larger than the size of the array.

The ASM will look the same from both of them, I'd expect, at a reasonable optimization level.

CMakeLists.txt Outdated Show resolved Hide resolved
* move _GLIBCXX_ASSERTIONS behind CMake option SONATA_CXX_WARNINGS
* don't use off_t, use size_t instead
* use iterator style access instead of raw pointers
Copy link
Contributor

@sergiorg-hpc sergiorg-hpc left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, looks good to me 👍. Thank you @mgeplf and @sanjayankur31 for the improvements!

@mgeplf mgeplf merged commit bfdf6f5 into BlueBrain:master Mar 17, 2022
@sergiorg-hpc sergiorg-hpc mentioned this pull request Mar 22, 2022
sergiorg-hpc added a commit that referenced this pull request Mar 22, 2022
sergiorg-hpc added a commit that referenced this pull request Mar 22, 2022
sergiorg-hpc added a commit that referenced this pull request Mar 30, 2022
sergiorg-hpc added a commit that referenced this pull request Mar 30, 2022
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.

None yet

4 participants