- if (dataQueue) {
- if (dataQueue->head != dataQueue->tail) {
- IODataQueueEntry * head = 0;
- UInt32 headSize = 0;
- UInt32 headOffset = dataQueue->head;
- UInt32 queueSize = getQueueSize();
-
- if (headOffset > queueSize) {
+ if (!dataQueue) {
+ return false;
+ }
+
+ // Read head and tail with acquire barrier
+ tailOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->tail, __ATOMIC_RELAXED);
+ headOffset = __c11_atomic_load((_Atomic UInt32 *)&dataQueue->head, __ATOMIC_ACQUIRE);
+
+ if (headOffset != tailOffset) {
+ IODataQueueEntry * head = 0;
+ UInt32 headSize = 0;
+ UInt32 queueSize = getQueueSize();
+
+ if (headOffset > queueSize) {
+ return false;
+ }
+
+ head = (IODataQueueEntry *)((char *)dataQueue->queue + headOffset);
+ headSize = head->size;
+
+ // we wrapped around to beginning, so read from there
+ // either there was not even room for the header
+ if ((headOffset > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
+ (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize) ||
+ // or there was room for the header, but not for the data
+ (headOffset + DATA_QUEUE_ENTRY_HEADER_SIZE > UINT32_MAX - headSize) ||
+ (headOffset + headSize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) {
+ // Note: we have to wrap to the beginning even with the UINT32_MAX checks
+ // because we have to support a queueSize of UINT32_MAX.
+ entry = dataQueue->queue;
+ entrySize = entry->size;
+ if ((entrySize > UINT32_MAX - DATA_QUEUE_ENTRY_HEADER_SIZE) ||
+ (entrySize + DATA_QUEUE_ENTRY_HEADER_SIZE > queueSize)) {