[ObjC] Error when appearing to use newer generated code.

There already are explicit checks in debug builds, but this adds an addition
check within all builds to catch when unknown flags are being passed to the
runtime, which is an indication that the source generation is from a newer
version of the library.

PiperOrigin-RevId: 506091257
pull/11727/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent d1a3c6d08b
commit 6e5a01bf72
  1. 41
      objectivec/GPBDescriptor.m
  2. 2
      objectivec/GPBDescriptor_PackagePrivate.h
  3. 7
      objectivec/GPBUtilities.m
  4. 6
      objectivec/GPBUtilities_PackagePrivate.h

@ -140,23 +140,47 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
flags:(GPBDescriptorInitializationFlags)flags {
// Compute the unknown flags by this version of the runtime and then check the passed in flags
// (from the generated code) to detect when sources from a newer version are being used with an
// older runtime.
GPBDescriptorInitializationFlags unknownFlags =
~(GPBDescriptorInitializationFlag_FieldsWithDefault |
GPBDescriptorInitializationFlag_WireFormat | GPBDescriptorInitializationFlag_UsesClassRefs |
GPBDescriptorInitializationFlag_Proto3OptionalKnown |
GPBDescriptorInitializationFlag_ClosedEnumSupportKnown);
if ((flags & unknownFlags) != 0) {
GPBRuntimeMatchFailure();
}
NSMutableArray *fields =
(fieldCount ? [[NSMutableArray alloc] initWithCapacity:fieldCount] : nil);
BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
void *desc;
GPBFieldFlags mergedFieldFlags = GPBFieldNone;
for (uint32_t i = 0; i < fieldCount; ++i) {
// Need correctly typed pointer for array indexing below to work.
if (fieldsIncludeDefault) {
desc = &(((GPBMessageFieldDescriptionWithDefault *)fieldDescriptions)[i]);
mergedFieldFlags |=
(((GPBMessageFieldDescriptionWithDefault *)fieldDescriptions)[i]).core.flags;
} else {
desc = &(((GPBMessageFieldDescription *)fieldDescriptions)[i]);
mergedFieldFlags |= (((GPBMessageFieldDescription *)fieldDescriptions)[i]).flags;
}
GPBFieldDescriptor *fieldDescriptor =
[[GPBFieldDescriptor alloc] initWithFieldDescription:desc file:file descriptorFlags:flags];
[fields addObject:fieldDescriptor];
[fieldDescriptor release];
}
// No real value in checking all the fields individually, just check the combined flags at the
// end.
GPBFieldFlags unknownFieldFlags =
~(GPBFieldRequired | GPBFieldRepeated | GPBFieldPacked | GPBFieldOptional |
GPBFieldHasDefaultValue | GPBFieldClearHasIvarOnZero | GPBFieldTextFormatNameCustom |
GPBFieldHasEnumDescriptor | GPBFieldMapKeyMask | GPBFieldClosedEnum);
if ((mergedFieldFlags & unknownFieldFlags) != 0) {
GPBRuntimeMatchFailure();
}
BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
@ -834,6 +858,14 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags {
// Compute the unknown flags by this version of the runtime and then check the passed in flags
// (from the generated code) to detect when sources from a newer version are being used with an
// older runtime.
GPBEnumDescriptorInitializationFlags unknownFlags =
~(GPBEnumDescriptorInitializationFlag_IsClosed);
if ((flags & unknownFlags) != 0) {
GPBRuntimeMatchFailure();
}
GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
valueNames:valueNames
values:values
@ -1072,6 +1104,15 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
usesClassRefs:(BOOL)usesClassRefs {
// Compute the unknown options by this version of the runtime and then check the passed in
// descriptor's options (from the generated code) to detect when sources from a newer version are
// being used with an older runtime.
GPBExtensionOptions unknownOptions =
~(GPBExtensionRepeated | GPBExtensionPacked | GPBExtensionSetWireFormat);
if ((desc->options & unknownOptions) != 0) {
GPBRuntimeMatchFailure();
}
if ((self = [super init])) {
description_ = desc;
if (!usesClassRefs) {

@ -263,6 +263,8 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
typedef NS_OPTIONS(uint32_t, GPBEnumDescriptorInitializationFlags) {
GPBEnumDescriptorInitializationFlag_None = 0,
// Available: 1 << 0
// Marks this enum as a closed enum.
GPBEnumDescriptorInitializationFlag_IsClosed = 1 << 1,
};

@ -228,6 +228,13 @@ void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) {
}
}
void GPBRuntimeMatchFailure(void) {
[NSException raise:NSInternalInconsistencyException
format:@"Proto generation source appears to have been from a"
@" version newer that this runtime (%d).",
GOOGLE_PROTOBUF_OBJC_VERSION];
}
// This api is no longer used for version checks. 30001 is the last version
// using this old versioning model. When that support is removed, this function
// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h).

@ -66,6 +66,12 @@ GPB_INLINE void GPB_DEBUG_CHECK_RUNTIME_VERSIONS(void) {
#endif
}
// Helper called within the library when the runtime detects something that
// indicates a older runtime is being used with newer generated code. Normally
// GPB_DEBUG_CHECK_RUNTIME_VERSIONS() gates this with a better message; this
// is just a final safety net to prevent otherwise hard to diagnose errors.
void GPBRuntimeMatchFailure(void);
// Legacy version of the checks, remove when GOOGLE_PROTOBUF_OBJC_GEN_VERSION
// goes away (see more info in GPBBootstrap.h).
void GPBCheckRuntimeVersionInternal(int32_t version);

Loading…
Cancel
Save