1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#import <stdatomic.h>
#import "GPBDescriptor_PackagePrivate.h"
#import "GPBExtensionRegistry.h"
#import "GPBMessage.h"
#import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBRootObject_PackagePrivate.h"
#import "GPBTestUtilities.h"
// This is a fake version, so the ptr check will fail.
static const int32_t FAKE_GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311 = 40311;
@interface MessageBadVersionFormatTest : GPBTestCase
@end
// clang-format off
// NOLINTBEGIN
// -------------------------------------------------------------------------------------------------
//
// This is extracted from generated code with the 40311 format but then edited so the pass in
// unknown values for the version support, the original proto was as follows:
//
// syntax = "proto2";
//
// enum EnumBadVersion {
// FOO = 0;
// BAR = 1;
// }
//
// message MessageBadVersion {
// optional EnumBadVersion value = 1;
// extensions 100 to max;
// }
//
// extend MessageBadVersion {
// optional MessageBadVersion other_m = 100;
// optional EnumBadVersion other_e = 101;
// }
//
// -------------------------------------------------------------------------------------------------
NS_ASSUME_NONNULL_BEGIN
typedef GPB_ENUM(EnumBadVersion) {
EnumBadVersion_Foo = 0,
EnumBadVersion_Bar = 1,
};
GPBEnumDescriptor *EnumBadVersion_EnumDescriptor(void);
BOOL EnumBadVersion_IsValidValue(int32_t value);
GPB_FINAL @interface TestBadVersionRoot : GPBRootObject
@end
@interface TestBadVersionRoot (DynamicMethods)
+ (GPBExtensionDescriptor *)otherM;
+ (GPBExtensionDescriptor *)otherE;
@end
typedef GPB_ENUM(MessageBadVersion_FieldNumber) {
MessageBadVersion_FieldNumber_Value = 1,
};
GPB_FINAL @interface MessageBadVersion : GPBMessage
@property(nonatomic, readwrite) EnumBadVersion value;
@property(nonatomic, readwrite) BOOL hasValue;
@end
NS_ASSUME_NONNULL_END
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
GPBObjCClassDeclaration(MessageBadVersion);
@implementation TestBadVersionRoot
+ (GPBExtensionRegistry*)extensionRegistry {
// This is called by +initialize so there is no need to worry
// about thread safety and initialization of registry.
static GPBExtensionRegistry* registry = nil;
if (!registry) {
registry = [[GPBExtensionRegistry alloc] init];
static GPBExtensionDescription descriptions[] = {
{
.defaultValue.valueMessage = nil,
.singletonName = GPBStringifySymbol(TestBadVersionRoot) "_otherM",
.extendedClass.clazz = GPBObjCClass(MessageBadVersion),
.messageOrGroupClass.clazz = GPBObjCClass(MessageBadVersion),
.enumDescriptorFunc = NULL,
.fieldNumber = 100,
.dataType = GPBDataTypeMessage,
.options = GPBExtensionNone,
},
{
.defaultValue.valueEnum = EnumBadVersion_Foo,
.singletonName = GPBStringifySymbol(TestBadVersionRoot) "_otherE",
.extendedClass.clazz = GPBObjCClass(MessageBadVersion),
.messageOrGroupClass.clazz = Nil,
.enumDescriptorFunc = EnumBadVersion_EnumDescriptor,
.fieldNumber = 101,
.dataType = GPBDataTypeEnum,
.options = GPBExtensionNone,
},
};
for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {
GPBExtensionDescriptor *extension =
[[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]
runtimeSupport:&FAKE_GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311];
[registry addExtension:extension];
[self globallyRegisterExtension:extension];
[extension release];
}
// None of the imports (direct or indirect) defined extensions, so no need to add
// them to this registry.
}
return registry;
}
@end
static GPBFilePackageAndPrefix TestBadVersionRoot_FileDescription = {
.package = NULL,
.prefix = NULL
};
GPBEnumDescriptor *EnumBadVersion_EnumDescriptor(void) {
static _Atomic(GPBEnumDescriptor*) descriptor = nil;
if (!descriptor) {
static const char *valueNames =
"Foo\000Bar\000";
static const int32_t values[] = {
EnumBadVersion_Foo,
EnumBadVersion_Bar,
};
GPBEnumDescriptor *worker =
[GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(EnumBadVersion)
runtimeSupport:&FAKE_GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311
valueNames:valueNames
values:values
count:(uint32_t)(sizeof(values) / sizeof(int32_t))
enumVerifier:EnumBadVersion_IsValidValue
flags:GPBEnumDescriptorInitializationFlag_IsClosed];
GPBEnumDescriptor *expected = nil;
if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {
[worker release];
}
}
return descriptor;
}
BOOL EnumBadVersion_IsValidValue(int32_t value__) {
switch (value__) {
case EnumBadVersion_Foo:
case EnumBadVersion_Bar:
return YES;
default:
return NO;
}
}
#pragma mark - MessageBadVersion
@implementation MessageBadVersion
@dynamic hasValue, value;
typedef struct MessageBadVersion__storage_ {
uint32_t _has_storage_[1];
EnumBadVersion value;
} MessageBadVersion__storage_;
+ (GPBDescriptor *)descriptor {
static GPBDescriptor *descriptor = nil;
if (!descriptor) {
static GPBMessageFieldDescription fields[] = {
{
.name = "value",
.dataTypeSpecific.enumDescFunc = EnumBadVersion_EnumDescriptor,
.number = MessageBadVersion_FieldNumber_Value,
.hasIndex = 0,
.offset = (uint32_t)offsetof(MessageBadVersion__storage_, value),
.flags = GPBFieldNone,
.dataType = GPBDataTypeEnum,
},
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:GPBObjCClass(MessageBadVersion)
messageName:@"MessageBadVersion"
runtimeSupport:&FAKE_GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311
fileDescription:&TestBadVersionRoot_FileDescription
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(MessageBadVersion__storage_)
flags:GPBDescriptorInitializationFlag_None];
static const GPBExtensionRange ranges[] = {
{ .start = 100, .end = 536870912 },
};
[localDescriptor setupExtensionRanges:ranges
count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
}
@end
#pragma clang diagnostic pop
// NOLINTEND
// clang-format on
// -------------------------------------------------------------------------------------------------
@implementation MessageBadVersionFormatTest
- (void)testMessageBadVersionFormat {
// Calling each one should try to start it up and result in a throw for an unknown version marker.
// Mostly this shouldn't happen as the symbol should be coming out of the runtime library so
// things should result in a link error before getting to the runtime check; this is just an added
// safety check.
XCTAssertThrowsSpecificNamed(EnumBadVersion_EnumDescriptor(), NSException,
NSInternalInconsistencyException);
XCTAssertThrowsSpecificNamed([TestBadVersionRoot otherM], NSException,
NSInternalInconsistencyException);
XCTAssertThrowsSpecificNamed([MessageBadVersion class], NSException,
NSInternalInconsistencyException);
}
@end
|