Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog

## [Unreleased] - 2026-10-05T11:47:00+05:30

### Fixed
- Suppressed spurious GCC `-Wstringop-overflow` diagnostic warning emitted under `-O2`/`-O3` optimization levels on GCC 14+ during `enqueue_bulk` with explicit producer tokens and dereferencing/generating iterators (Issue #456).
- Added `__GNUC__ >= 7` guarded localized diagnostic pragma to `ConcurrentQueue::inner_enqueue_bulk`.

### Added
- Added unit test `enqueue_bulk_producer_token_generating_iterator` covering bulk enqueue operations with explicit producer tokens, move-only objects, and generating iterators.

### Files Affected
- `concurrentqueue.h`
- `tests/unittests/unittests.cpp`
7 changes: 7 additions & 0 deletions concurrentqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,14 @@ class ConcurrentQueue
template<AllocationMode canAlloc, typename It>
inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
return static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk<canAlloc>(itemFirst, count);
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7
#pragma GCC diagnostic pop
#endif
}

template<AllocationMode canAlloc, typename It>
Expand Down
53 changes: 53 additions & 0 deletions tests/unittests/unittests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ class ConcurrentQueueTests : public TestClass<ConcurrentQueueTests>
REGISTER_TEST(explicit_strings_threaded);
REGISTER_TEST(large_traits);
REGISTER_TEST(implicit_producer_index_limit);
REGISTER_TEST(enqueue_bulk_producer_token_generating_iterator);
}

bool postTest(bool testSucceeded) override
Expand Down Expand Up @@ -5134,6 +5135,58 @@ class ConcurrentQueueTests : public TestClass<ConcurrentQueueTests>

return true;
}

/**
* @brief Verifies bulk enqueuing using an explicit producer token with a generating iterator
* and move-only types, validating avoidance of -Wstringop-overflow false positive (Issue #456).
*
* @return true if all assertions succeed.
*/
bool enqueue_bulk_producer_token_generating_iterator()
{
struct MoveOnlyTask {
int id;
alignas(16) char storage[48];
MoveOnlyTask() : id(-1) { std::memset(storage, 0, sizeof(storage)); }
explicit MoveOnlyTask(int id) : id(id) { std::memset(storage, 0, sizeof(storage)); }
MoveOnlyTask(MoveOnlyTask&& o) MOODYCAMEL_NOEXCEPT : id(o.id) {
o.id = -1;
std::memcpy(storage, o.storage, sizeof(storage));
}
MoveOnlyTask& operator=(MoveOnlyTask&& o) MOODYCAMEL_NOEXCEPT {
id = o.id;
o.id = -1;
std::memcpy(storage, o.storage, sizeof(storage));
return *this;
}
MoveOnlyTask(const MoveOnlyTask&) MOODYCAMEL_DELETE_FUNCTION;
MoveOnlyTask& operator=(const MoveOnlyTask&) MOODYCAMEL_DELETE_FUNCTION;
};

struct GeneratorIterator {
int current;
MoveOnlyTask operator*() const { return MoveOnlyTask(current); }
GeneratorIterator& operator++() { ++current; return *this; }
GeneratorIterator operator++(int) { GeneratorIterator copy = *this; ++current; return copy; }
bool operator!=(const GeneratorIterator& o) const { return current != o.current; }
};

ConcurrentQueue<MoveOnlyTask> q;
ProducerToken tok(q);
GeneratorIterator it{0};
const size_t COUNT = 64;
ASSERT_OR_FAIL(q.enqueue_bulk(tok, it, COUNT));

for (size_t i = 0; i != COUNT; ++i) {
MoveOnlyTask task;
ASSERT_OR_FAIL(q.try_dequeue(task));
ASSERT_OR_FAIL(task.id == static_cast<int>(i));
}
MoveOnlyTask extra;
ASSERT_OR_FAIL(!q.try_dequeue(extra));

return true;
}
};

}
Expand Down