-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[libc++][test] Improve ThrowingT to Accurately Throw after throw_after > 1 Use #114077
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
Conversation
@llvm/pr-subscribers-libcxx Author: Peng Liu (winner245) ChangesSummaryThis PR proposes an improvement to the It seems that this issue was not previously discovered because all exception tests for DetailsThe The proposed changes include initializing Test#include <iostream>
#include <vector>
struct ThrowingT {
int* throw_after_n_ = nullptr;
ThrowingT() { throw 0; }
ThrowingT(int& throw_after_n) : throw_after_n_(&throw_after_n) {
if (throw_after_n == 0)
throw 0;
--throw_after_n;
}
ThrowingT(const ThrowingT&) {
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
}
ThrowingT& operator=(const ThrowingT&) {
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
return *this;
}
};
struct ThrowingT_Fix {
int* throw_after_n_ = nullptr;
ThrowingT_Fix() { throw 0; }
ThrowingT_Fix(int& throw_after_n) : throw_after_n_(&throw_after_n) {
if (throw_after_n == 0)
throw 0;
--throw_after_n;
}
ThrowingT_Fix(const ThrowingT_Fix& rhs) : throw_after_n_{rhs.throw_after_n_} {
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
}
ThrowingT_Fix& operator=(const ThrowingT_Fix& rhs) {
throw_after_n_ = rhs.throw_after_n_;
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
return *this;
}
};
int main() {
try { // Throw in vector(size_type, value_type) from type
int throw_after = 999;
ThrowingT v(throw_after);
std::vector<ThrowingT> get_alloc(1, v); // This should not throw!
} catch (int) {
std::cout << "get_alloc(1, v) throwed unexpectedly\n";
}
try { // Throw in vector(size_type, value_type) from type
int throw_after = 999;
ThrowingT_Fix v(throw_after);
std::vector<ThrowingT_Fix> get_alloc(998, v); // do not throw, as expected
} catch (int) {
std::cout << "get_alloc(998, v) throwed unexpectedly\n";
}
std::cout << "get_alloc(998, v) did not throw as expected\n";
try { // Throw in vector(size_type, value_type) from type
int throw_after = 999;
ThrowingT_Fix v(throw_after);
std::vector<ThrowingT_Fix> get_alloc(999, v); // throw, as expected
} catch (int) {
std::cout << "get_alloc(999, v) throwed as expected\n";
}
} Testing Result
|
1fa6792
to
08e677d
Compare
Thanks a lot for the fix -- good find! |
…r > 1 Use (llvm#114077) This PR fixes the `ThrowingT` class, which currently fails to raise exceptions after a specified number of copy construction operations. The class is intended to throw in a controlled manner based on a specified counter value `throw_after`. However, its current implementation of the copy constructor fails to achieve this goal. The problem arises because the copy constructor does not initialize the `throw_after_n_` member, leaving `throw_after_n_` to default to `nullptr` as defined by the in-class initializer. As a result, its copy constructor always checks against `nullptr`, causing an immediate exception rather than throwing after the specified number `throw_after` of uses. The fix is straightforward: simply initialize the `throw_after_n_` member in the member initializer list. This issue was previously uncovered because all exception tests for `std::vector` in `exceptions.pass.cpp` used a `throw_after` value of 1, which coincidentally aligned with the class's behavior.
This PR fixes the
ThrowingT
class, which currently fails to raise exceptions after a specified number of copy construction operations. The class is intended to throw in a controlled manner based on a specified counter valuethrow_after
. However, its current implementation of the copy constructor fails to achieve this goal.The problem arises because the copy constructor does not initialize the
throw_after_n_
member, leavingthrow_after_n_
to default tonullptr
as defined by the in-class initializer (int* throw_after_n_ = nullptr;
). As a result, its copy constructor always checks againstnullptr
, causing an immediate exception rather than throwing after the specified numberthrow_after
of uses. The fix is straightforward: simply initialize thethrow_after_n_
member in the member initializer list.This issue was previously uncovered because all exception tests for
std::vector
inexceptions.pass.cpp
used athrow_after
value of 1, which coincidentally aligned with the class's behavior.A small test demonstrating the improper behavior of
ThrowingT
is available at Godbolt link.