diff options
Diffstat (limited to 'objectivec')
-rw-r--r-- | objectivec/GPBCodedInputStream.m | 2 | ||||
-rw-r--r-- | objectivec/GPBDescriptor.m | 6 | ||||
-rw-r--r-- | objectivec/GPBMessage.m | 48 | ||||
-rw-r--r-- | objectivec/GPBMessage_PackagePrivate.h | 14 | ||||
-rw-r--r-- | objectivec/GPBUtilities.m | 32 | ||||
-rw-r--r-- | objectivec/GPBUtilities_PackagePrivate.h | 4 | ||||
-rw-r--r-- | objectivec/Tests/GPBCodedInputStreamTests.m | 2 | ||||
-rw-r--r-- | objectivec/Tests/GPBCodedOuputStreamTests.m | 2 | ||||
-rw-r--r-- | objectivec/Tests/GPBUtilitiesTests.m | 8 | ||||
-rw-r--r-- | objectivec/google/protobuf/Struct.pbobjc.m | 2 | ||||
-rw-r--r-- | objectivec/google/protobuf/Type.pbobjc.m | 6 |
11 files changed, 67 insertions, 59 deletions
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m index 0759640d..a8262e5d 100644 --- a/objectivec/GPBCodedInputStream.m +++ b/objectivec/GPBCodedInputStream.m @@ -110,7 +110,7 @@ static int64_t ReadRawVarint64(GPBCodedInputStreamState *state) { int64_t result = 0; while (shift < 64) { int8_t b = ReadRawByte(state); - result |= (int64_t)(b & 0x7F) << shift; + result |= (int64_t)((uint64_t)(b & 0x7F) << shift); if ((b & 0x80) == 0) { return result; } diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m index 3c3844da..615d2234 100644 --- a/objectivec/GPBDescriptor.m +++ b/objectivec/GPBDescriptor.m @@ -548,7 +548,8 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { // descriptor structure. const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; if (bytes) { - uint32_t length = *((uint32_t *)bytes); + uint32_t length; + memcpy(&length, bytes, sizeof(length)); length = ntohl(length); bytes += sizeof(length); defaultValue_.valueData = @@ -963,7 +964,8 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { const uint8_t *bytes = (const uint8_t *)description->defaultValue.valueData; if (bytes) { - uint32_t length = *((uint32_t *)bytes); + uint32_t length; + memcpy(&length, bytes, sizeof(length)); // The length is stored in network byte order. length = ntohl(length); bytes += sizeof(length); diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index a9f8bfe7..db5d3b60 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -78,6 +78,20 @@ static NSString *const kGPBDataCoderKey = @"GPBData"; GPBMessage *autocreator_; GPBFieldDescriptor *autocreatorField_; GPBExtensionDescriptor *autocreatorExtension_; + + // A lock to provide mutual exclusion from internal data that can be modified + // by *read* operations such as getters (autocreation of message fields and + // message extensions, not setting of values). Used to guarantee thread safety + // for concurrent reads on the message. + // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have + // pointed out that they are vulnerable to live locking on iOS in cases of + // priority inversion: + // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/ + // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html + // Use of readOnlySemaphore_ must be prefaced by a call to + // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows + // readOnlySemaphore_ to be only created when actually needed. + _Atomic(dispatch_semaphore_t) readOnlySemaphore_; } @end @@ -753,6 +767,12 @@ void GPBPrepareReadOnlySemaphore(GPBMessage *self) { if (!atomic_compare_exchange_strong(&self->readOnlySemaphore_, &expected, worker)) { dispatch_release(worker); } +#if defined(__clang_analyzer__) + // The Xcode 9.2 (and 9.3 beta) static analyzer thinks worker is leaked + // (doesn't seem to know about atomic_compare_exchange_strong); so just + // for the analyzer, let it think worker is also released in this case. + else { dispatch_release(worker); } +#endif } #pragma clang diagnostic pop @@ -3266,4 +3286,32 @@ id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) { return GetOrCreateMapIvarWithField(self, field, syntax); } +id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { + NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here"); + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + return *typePtr; + } + // Not set... + + // Non messages (string/data), get their default. + if (!GPBFieldDataTypeIsMessage(field)) { + return field.defaultValue.valueMessage; + } + + GPBPrepareReadOnlySemaphore(self); + dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); + GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!result) { + // For non repeated messages, create the object, set it and return it. + // This object will not initially be visible via GPBGetHasIvar, so + // we save its creator so it can become visible if it's mutated later. + result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); + GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); + } + dispatch_semaphore_signal(self->readOnlySemaphore_); + return result; +} + #pragma clang diagnostic pop diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h index 366e5bbf..ca10983b 100644 --- a/objectivec/GPBMessage_PackagePrivate.h +++ b/objectivec/GPBMessage_PackagePrivate.h @@ -61,20 +61,6 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; // GPBMessage_Storage with _has_storage__ as the first field. // Kept public because static functions need to access it. GPBMessage_StoragePtr messageStorage_; - - // A lock to provide mutual exclusion from internal data that can be modified - // by *read* operations such as getters (autocreation of message fields and - // message extensions, not setting of values). Used to guarantee thread safety - // for concurrent reads on the message. - // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have - // pointed out that they are vulnerable to live locking on iOS in cases of - // priority inversion: - // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/ - // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html - // Use of readOnlySemaphore_ must be prefaced by a call to - // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows - // readOnlySemaphore_ to be only created when actually needed. - _Atomic(dispatch_semaphore_t) readOnlySemaphore_; } // Gets an extension value without autocreating the result if not found. (i.e. diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index 77ea9577..e2a12ca4 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -291,7 +291,7 @@ BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) { } else { NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); uint32_t byteIndex = idx / 32; - uint32_t bitMask = (1 << (idx % 32)); + uint32_t bitMask = (1U << (idx % 32)); BOOL hasIvar = (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO; return hasIvar; @@ -315,7 +315,7 @@ void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); uint32_t *has_storage = self->messageStorage_->_has_storage_; uint32_t byte = idx / 32; - uint32_t bitMask = (1 << (idx % 32)); + uint32_t bitMask = (1U << (idx % 32)); if (value) { has_storage[byte] |= bitMask; } else { @@ -628,34 +628,6 @@ id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self, return *typePtr; } -id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { - NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here"); - if (GPBGetHasIvarField(self, field)) { - uint8_t *storage = (uint8_t *)self->messageStorage_; - id *typePtr = (id *)&storage[field->description_->offset]; - return *typePtr; - } - // Not set... - - // Non messages (string/data), get their default. - if (!GPBFieldDataTypeIsMessage(field)) { - return field.defaultValue.valueMessage; - } - - GPBPrepareReadOnlySemaphore(self); - dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); - GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); - if (!result) { - // For non repeated messages, create the object, set it and return it. - // This object will not initially be visible via GPBGetHasIvar, so - // we save its creator so it can become visible if it's mutated later. - result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); - GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); - } - dispatch_semaphore_signal(self->readOnlySemaphore_); - return result; -} - // Only exists for public api, no core code should use this. int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) { GPBFileSyntax syntax = [self descriptor].file.syntax; diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h index c8b21ed7..ed424ce3 100644 --- a/objectivec/GPBUtilities_PackagePrivate.h +++ b/objectivec/GPBUtilities_PackagePrivate.h @@ -124,7 +124,7 @@ GPB_INLINE int64_t GPBDecodeZigZag64(uint64_t n) { // thus always taking 10 bytes on the wire.) GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) { // Note: the right-shift must be arithmetic - return (uint32_t)((n << 1) ^ (n >> 31)); + return ((uint32_t)n << 1) ^ (uint32_t)(n >> 31); } // Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers @@ -133,7 +133,7 @@ GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) { // thus always taking 10 bytes on the wire.) GPB_INLINE uint64_t GPBEncodeZigZag64(int64_t n) { // Note: the right-shift must be arithmetic - return (uint64_t)((n << 1) ^ (n >> 63)); + return ((uint64_t)n << 1) ^ (uint64_t)(n >> 63); } #pragma clang diagnostic push diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m index 11f7ceaf..f5aa6903 100644 --- a/objectivec/Tests/GPBCodedInputStreamTests.m +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -220,7 +220,7 @@ 0xa6, 0x01) value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) | - (0x05LL << 49) | (0x26LL << 56) | (0x01LL << 63)]; + (0x05LL << 49) | (0x26LL << 56) | (0x01ULL << 63)]; // Failures [self assertReadVarintFailure:bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m index 2ad326be..878e7aa9 100644 --- a/objectivec/Tests/GPBCodedOuputStreamTests.m +++ b/objectivec/Tests/GPBCodedOuputStreamTests.m @@ -266,7 +266,7 @@ value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) | (0x05LL << 49) | (0x26LL << 56) | - (0x01LL << 63)]; + (0x01ULL << 63)]; } - (void)testWriteLittleEndian { diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m index 2e206a54..8a8ba93e 100644 --- a/objectivec/Tests/GPBUtilitiesTests.m +++ b/objectivec/Tests/GPBUtilitiesTests.m @@ -52,12 +52,12 @@ - (void)testRightShiftFunctions { XCTAssertEqual((1UL << 31) >> 31, 1UL); - XCTAssertEqual((1 << 31) >> 31, -1); + XCTAssertEqual((int32_t)(1U << 31) >> 31, -1); XCTAssertEqual((1ULL << 63) >> 63, 1ULL); - XCTAssertEqual((1LL << 63) >> 63, -1LL); + XCTAssertEqual((int64_t)(1ULL << 63) >> 63, -1LL); - XCTAssertEqual(GPBLogicalRightShift32((1 << 31), 31), 1); - XCTAssertEqual(GPBLogicalRightShift64((1LL << 63), 63), 1LL); + XCTAssertEqual(GPBLogicalRightShift32((1U << 31), 31), 1); + XCTAssertEqual(GPBLogicalRightShift64((1ULL << 63), 63), 1LL); } - (void)testGPBDecodeTextFormatName { diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m index 6d9d7b75..816fd6df 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.m +++ b/objectivec/google/protobuf/Struct.pbobjc.m @@ -53,7 +53,7 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) { #pragma mark - Enum GPBNullValue GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) { - static _Atomic(GPBEnumDescriptor*) descriptor = NULL; + static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "NullValue\000"; diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m index 981ae4d4..bb64d876 100644 --- a/objectivec/google/protobuf/Type.pbobjc.m +++ b/objectivec/google/protobuf/Type.pbobjc.m @@ -56,7 +56,7 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) { #pragma mark - Enum GPBSyntax GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void) { - static _Atomic(GPBEnumDescriptor*) descriptor = NULL; + static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "SyntaxProto2\000SyntaxProto3\000"; @@ -371,7 +371,7 @@ void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) { #pragma mark - Enum GPBField_Kind GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) { - static _Atomic(GPBEnumDescriptor*) descriptor = NULL; + static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "TypeUnknown\000TypeDouble\000TypeFloat\000TypeInt" @@ -445,7 +445,7 @@ BOOL GPBField_Kind_IsValidValue(int32_t value__) { #pragma mark - Enum GPBField_Cardinality GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) { - static _Atomic(GPBEnumDescriptor*) descriptor = NULL; + static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "CardinalityUnknown\000CardinalityOptional\000C" |