Skip to content

Commit 33debf3

Browse files
habermanmkruskal-google
authored andcommitted
Fixed two GCC-only issues around upb's generated extension registry.
This change refactors the generated `upb_MiniTableExtension` variables to be `const upb_MiniTableExtension*` instead of `const upb_MiniTableExtension`. The linker array now stores pointers to these extension objects. This fixes an issue related to position-independent executables on GCC (see the attached bug for more information). We also unconditionally retain all extensions for the generated registry when compiling under GCC. This effectively disables tree shaking of extensions when compiling with GCC, but fixes a GCC-only compiler error. There may be a way to re-enable linker GC with GCC at some point, but the priority for the moment is just fixing the issue. A new test is added to verify registry loading with no linked extensions. Fixes: #26385 PiperOrigin-RevId: 906412231
1 parent 08d520a commit 33debf3

14 files changed

Lines changed: 158 additions & 48 deletions

hpb/backend/upb/extension.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,19 +184,19 @@ class ExtensionIdentifier {
184184

185185
// Placeholder for extant legacy callers, avoid use if possible
186186
const upb_MiniTableExtension* mini_table_ext() const {
187-
return mini_table_ext_;
187+
return *mini_table_ext_;
188188
}
189189

190190
private:
191191
constexpr explicit ExtensionIdentifier(
192-
const upb_MiniTableExtension* mte,
192+
const upb_MiniTableExtension* const* mte,
193193
typename UpbExtensionTrait<ExtensionType>::DefaultType val,
194194
uint32_t number)
195195
: mini_table_ext_(mte), default_val_(val), number_(number) {}
196196

197197
constexpr uint32_t number() const { return number_; }
198198

199-
const upb_MiniTableExtension* mini_table_ext_;
199+
const upb_MiniTableExtension* const* mini_table_ext_;
200200

201201
typename UpbExtensionTrait<ExtensionType>::ReturnType default_value() const {
202202
if constexpr (IsHpbClass<ExtensionType>) {

upb/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ filegroup(
303303
"//src/google/protobuf:well_known_type_protos",
304304
"//upb/json:test_protos",
305305
"//upb/message:test_protos",
306+
"//upb/mini_table:test_protos",
306307
"//upb/test:test_protos",
307308
"//upb/util:test_protos",
308309
],

upb/message/promote_test.cc

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,12 @@ TEST(GeneratedCode, FindUnknown) {
8181

8282
upb_FindUnknownRet result = upb_Message_FindUnknown(
8383
UPB_UPCAST(base_msg),
84-
upb_MiniTableExtension_Number(&upb_test_ModelExtension1_model_ext_ext),
85-
0);
84+
upb_MiniTableExtension_Number(upb_test_ModelExtension1_model_ext_ext), 0);
8685
EXPECT_EQ(kUpb_FindUnknown_Ok, result.status);
8786

8887
result = upb_Message_FindUnknown(
8988
UPB_UPCAST(base_msg),
90-
upb_MiniTableExtension_Number(&upb_test_ModelExtension2_model_ext_ext),
91-
0);
89+
upb_MiniTableExtension_Number(upb_test_ModelExtension2_model_ext_ext), 0);
9290
EXPECT_EQ(kUpb_FindUnknown_NotPresent, result.status);
9391

9492
upb_Arena_Free(arena);
@@ -125,7 +123,7 @@ TEST(GeneratedCode, PromoteFromMultiple) {
125123

126124
upb_MessageValue value;
127125
upb_GetExtension_Status result = upb_Message_GetOrPromoteExtension(
128-
UPB_UPCAST(parsed), &upb_test_ModelExtension1_model_ext_ext, options,
126+
UPB_UPCAST(parsed), upb_test_ModelExtension1_model_ext_ext, options,
129127
arena, &value);
130128
ASSERT_EQ(result, kUpb_GetExtension_Ok);
131129
upb_test_ModelExtension1* parsed_ex =
@@ -135,8 +133,7 @@ TEST(GeneratedCode, PromoteFromMultiple) {
135133

136134
upb_FindUnknownRet found = upb_Message_FindUnknown(
137135
UPB_UPCAST(parsed),
138-
upb_MiniTableExtension_Number(&upb_test_ModelExtension1_model_ext_ext),
139-
0);
136+
upb_MiniTableExtension_Number(upb_test_ModelExtension1_model_ext_ext), 0);
140137
EXPECT_EQ(kUpb_FindUnknown_NotPresent, found.status);
141138

142139
upb_Arena_Free(arena);
@@ -188,7 +185,7 @@ TEST(GeneratedCode, Extensions) {
188185

189186
// Test known GetExtension 1
190187
promote_status = upb_Message_GetOrPromoteExtension(
191-
UPB_UPCAST(msg), &upb_test_ModelExtension1_model_ext_ext, 0, arena,
188+
UPB_UPCAST(msg), upb_test_ModelExtension1_model_ext_ext, 0, arena,
192189
&value);
193190
ext1 = (upb_test_ModelExtension1*)value.msg_val;
194191
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -197,39 +194,39 @@ TEST(GeneratedCode, Extensions) {
197194

198195
// Test known GetExtension 2
199196
promote_status = upb_Message_GetOrPromoteExtension(
200-
UPB_UPCAST(msg), &upb_test_ModelExtension2_model_ext_ext, 0, arena,
197+
UPB_UPCAST(msg), upb_test_ModelExtension2_model_ext_ext, 0, arena,
201198
&value);
202199
ext2 = (upb_test_ModelExtension2*)value.msg_val;
203200
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
204201
EXPECT_EQ(5, upb_test_ModelExtension2_i(ext2));
205202

206203
// Test known GetExtension 3
207204
promote_status = upb_Message_GetOrPromoteExtension(
208-
UPB_UPCAST(msg), &upb_test_ModelExtension2_model_ext_2_ext, 0, arena,
205+
UPB_UPCAST(msg), upb_test_ModelExtension2_model_ext_2_ext, 0, arena,
209206
&value);
210207
ext2 = (upb_test_ModelExtension2*)value.msg_val;
211208
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
212209
EXPECT_EQ(6, upb_test_ModelExtension2_i(ext2));
213210

214211
// Test known GetExtension 4
215212
promote_status = upb_Message_GetOrPromoteExtension(
216-
UPB_UPCAST(msg), &upb_test_ModelExtension2_model_ext_3_ext, 0, arena,
213+
UPB_UPCAST(msg), upb_test_ModelExtension2_model_ext_3_ext, 0, arena,
217214
&value);
218215
ext2 = (upb_test_ModelExtension2*)value.msg_val;
219216
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
220217
EXPECT_EQ(7, upb_test_ModelExtension2_i(ext2));
221218

222219
// Test known GetExtension 5
223220
promote_status = upb_Message_GetOrPromoteExtension(
224-
UPB_UPCAST(msg), &upb_test_ModelExtension2_model_ext_4_ext, 0, arena,
221+
UPB_UPCAST(msg), upb_test_ModelExtension2_model_ext_4_ext, 0, arena,
225222
&value);
226223
ext2 = (upb_test_ModelExtension2*)value.msg_val;
227224
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
228225
EXPECT_EQ(8, upb_test_ModelExtension2_i(ext2));
229226

230227
// Test known GetExtension 6
231228
promote_status = upb_Message_GetOrPromoteExtension(
232-
UPB_UPCAST(msg), &upb_test_ModelExtension2_model_ext_5_ext, 0, arena,
229+
UPB_UPCAST(msg), upb_test_ModelExtension2_model_ext_5_ext, 0, arena,
233230
&value);
234231
ext2 = (upb_test_ModelExtension2*)value.msg_val;
235232
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -246,7 +243,7 @@ TEST(GeneratedCode, Extensions) {
246243

247244
// Test unknown GetExtension.
248245
promote_status = upb_Message_GetOrPromoteExtension(
249-
UPB_UPCAST(base_msg), &upb_test_ModelExtension1_model_ext_ext, 0, arena,
246+
UPB_UPCAST(base_msg), upb_test_ModelExtension1_model_ext_ext, 0, arena,
250247
&value);
251248
ext1 = (upb_test_ModelExtension1*)value.msg_val;
252249
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -256,7 +253,7 @@ TEST(GeneratedCode, Extensions) {
256253

257254
// Test unknown GetExtension.
258255
promote_status = upb_Message_GetOrPromoteExtension(
259-
UPB_UPCAST(base_msg), &upb_test_ModelExtension2_model_ext_ext, 0, arena,
256+
UPB_UPCAST(base_msg), upb_test_ModelExtension2_model_ext_ext, 0, arena,
260257
&value);
261258
ext2 = (upb_test_ModelExtension2*)value.msg_val;
262259
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -265,7 +262,7 @@ TEST(GeneratedCode, Extensions) {
265262

266263
// Test unknown GetExtension.
267264
promote_status = upb_Message_GetOrPromoteExtension(
268-
UPB_UPCAST(base_msg), &upb_test_ModelExtension2_model_ext_2_ext, 0, arena,
265+
UPB_UPCAST(base_msg), upb_test_ModelExtension2_model_ext_2_ext, 0, arena,
269266
&value);
270267
ext2 = (upb_test_ModelExtension2*)value.msg_val;
271268
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -274,7 +271,7 @@ TEST(GeneratedCode, Extensions) {
274271

275272
// Test unknown GetExtension.
276273
promote_status = upb_Message_GetOrPromoteExtension(
277-
UPB_UPCAST(base_msg), &upb_test_ModelExtension2_model_ext_3_ext, 0, arena,
274+
UPB_UPCAST(base_msg), upb_test_ModelExtension2_model_ext_3_ext, 0, arena,
278275
&value);
279276
ext2 = (upb_test_ModelExtension2*)value.msg_val;
280277
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -283,7 +280,7 @@ TEST(GeneratedCode, Extensions) {
283280

284281
// Test unknown GetExtension.
285282
promote_status = upb_Message_GetOrPromoteExtension(
286-
UPB_UPCAST(base_msg), &upb_test_ModelExtension2_model_ext_4_ext, 0, arena,
283+
UPB_UPCAST(base_msg), upb_test_ModelExtension2_model_ext_4_ext, 0, arena,
287284
&value);
288285
ext2 = (upb_test_ModelExtension2*)value.msg_val;
289286
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);
@@ -292,7 +289,7 @@ TEST(GeneratedCode, Extensions) {
292289

293290
// Test unknown GetExtension.
294291
promote_status = upb_Message_GetOrPromoteExtension(
295-
UPB_UPCAST(base_msg), &upb_test_ModelExtension2_model_ext_5_ext, 0, arena,
292+
UPB_UPCAST(base_msg), upb_test_ModelExtension2_model_ext_5_ext, 0, arena,
296293
&value);
297294
ext2 = (upb_test_ModelExtension2*)value.msg_val;
298295
EXPECT_EQ(kUpb_GetExtension_Ok, promote_status);

upb/mini_table/BUILD

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,28 @@ cc_test(
148148
],
149149
)
150150

151+
cc_test(
152+
name = "generated_registry_empty_test",
153+
srcs = ["generated_registry_empty_test.cc"],
154+
linkstatic = 1,
155+
deps = [
156+
":generated_registry_empty_test_upb_minitable_proto",
157+
":mini_table",
158+
"@googletest//:gtest",
159+
"@googletest//:gtest_main",
160+
],
161+
)
162+
163+
proto_library(
164+
name = "generated_registry_empty_test_proto",
165+
srcs = ["generated_registry_empty_test.proto"],
166+
)
167+
168+
upb_minitable_proto_library(
169+
name = "generated_registry_empty_test_upb_minitable_proto",
170+
deps = [":generated_registry_empty_test_proto"],
171+
)
172+
151173
proto_library(
152174
name = "message_benchmark_proto",
153175
testonly = 1,
@@ -232,3 +254,13 @@ filegroup(
232254
),
233255
visibility = ["//upb:__pkg__"],
234256
)
257+
258+
filegroup(
259+
name = "test_protos",
260+
srcs = glob(
261+
[
262+
"**/*test.proto",
263+
],
264+
),
265+
visibility = ["//upb:__pkg__"],
266+
)

upb/mini_table/extension_registry.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
100100
return NULL;
101101
}
102102
}
103+
104+
size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r) {
105+
return upb_strtable_count(&r->exts);
106+
}

upb/mini_table/extension_registry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray(
8484
UPB_API const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
8585
const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num);
8686

87+
// Returns the number of extensions in the registry. For testing/debugging only.
88+
UPB_API size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r);
89+
8790
#ifdef __cplusplus
8891
} /* extern "C" */
8992
#endif

upb/mini_table/generated_registry.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,24 @@ static bool _upb_GeneratedRegistry_AddAllLinkedExtensions(
4242
const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* entry =
4343
UPB_PRIVATE(upb_generated_extension_list);
4444
while (entry != NULL) {
45-
const char* current = (const char*)entry->start;
46-
const char* end = (const char*)entry->stop;
47-
while ((size_t)(end - current) >= sizeof(upb_MiniTableExtension)) {
48-
const upb_MiniTableExtension* ext =
49-
(const upb_MiniTableExtension*)current;
45+
const upb_MiniTableExtension** current = entry->start;
46+
for (current = entry->start; current != entry->stop; ++current) {
47+
const upb_MiniTableExtension* ext = *current;
5048
// Sentinels and padding introduced by the linker can result in zeroed
5149
// entries, so simply skip them.
52-
if (upb_MiniTableExtension_Number(ext) == 0) {
50+
if (*current == NULL) {
5351
// MSVC introduces padding that might not be sized exactly the same as
54-
// upb_MiniTableExtension, so we can't iterate by sizeof. This is a
55-
// valid thing for any linker to do, so it's safer to just always do it.
56-
current += UPB_ALIGN_OF(upb_MiniTableExtension);
52+
// the linker array element, but it should be properly aligned, so just
53+
// skipping empty elements should be safe. (If the size and align of
54+
// the array elements was different, we'd have to do something more
55+
// complicated).
5756
continue;
5857
}
5958

6059
if (upb_ExtensionRegistry_Add(r, ext) !=
6160
kUpb_ExtensionRegistryStatus_Ok) {
6261
return false;
6362
}
64-
current += sizeof(upb_MiniTableExtension);
6563
}
6664
entry = entry->next;
6765
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
#include <gtest/gtest.h>
3+
#include "upb/mini_table/extension_registry.h"
4+
#include "upb/mini_table/generated_registry.h"
5+
#include "upb/mini_table/generated_registry_empty_test.upb_minitable.h"
6+
#include "upb/mini_table/message.h"
7+
8+
namespace {
9+
10+
// Tests that we can instantiate the registry even if no extensions are linked.
11+
// This ensures that the sentinel object in the linker array properly ensures
12+
// that the encapsulation symbols are defined (eg. __start_linkarr_exts,
13+
// __stop_linkarr_exts) even when no extensions were linked.
14+
TEST(GeneratedRegistryEmptyTest, Instantiate) {
15+
// Strongly reference the generated MiniTable to ensure that the TU for
16+
// generated_registry_empty_test.upb_minitable.c is pulled in.
17+
const upb_MiniTable* volatile table =
18+
&upb_0test_0empty_0registry__EmptyRegistryTestMessage_msg_init;
19+
(void)table;
20+
21+
// Test that the registry can be loaded, even if no extensions are linked.
22+
// If we did not have a sentinel in the linker array, we would get a linker
23+
// error here like:
24+
//
25+
// ld: error: undefined symbol: __start_linkarr_upb_AllExts
26+
// >>> referenced by generated_registry_empty_test.upb_minitable.c
27+
// >>>
28+
// generated_registry_empty_test.upb_minitable.pic.o:(upb_GeneratedRegistry_Constructor_dont_copy_me__upb_internal_use_only.entry)
29+
// >>> the encapsulation symbol needs to be retained under --gc-sections
30+
// properly; consider -z nostart-stop-gc (see
31+
// https://lld.llvm.org/ELF/start-stop-gc)
32+
//
33+
// ld: error: undefined symbol: __stop_linkarr_upb_AllExts
34+
// >>> referenced by generated_registry_empty_test.upb_minitable.c
35+
// >>>
36+
// generated_registry_empty_test.upb_minitable.pic.o:(upb_GeneratedRegistry_Constructor_dont_copy_me__upb_internal_use_only.entry)
37+
const upb_GeneratedRegistryRef* ref = upb_GeneratedRegistry_Load();
38+
EXPECT_NE(ref, nullptr);
39+
const upb_ExtensionRegistry* reg = upb_GeneratedRegistry_Get(ref);
40+
EXPECT_NE(reg, nullptr);
41+
42+
upb_GeneratedRegistry_Release(ref);
43+
}
44+
45+
} // namespace
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
edition = "2024";
2+
3+
package upb_test_empty_registry;
4+
5+
// A message that is in the same file as the unused extension.
6+
message EmptyRegistryTestMessage {
7+
extensions 1 to max;
8+
}
9+
10+
// An extension that we will *not* reference. The existence of this extension
11+
// will cause us to emit the code to register all extensions, but since this
12+
// extension is never referenced, that list of extensions will be empty.
13+
extend EmptyRegistryTestMessage {
14+
int32 unused_extension = 1;
15+
}

upb/mini_table/generated_registry_test.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ TEST_F(GeneratedRegistryTest, LocalExtensionExists) {
4343
// to be linked in.
4444

4545
// Force linkage and sanity check extension numbers.
46-
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_test_2023_ext_ext), 100);
46+
ASSERT_EQ(upb_MiniTableExtension_Number(upb_test_2023_ext_ext), 100);
4747

4848
EXPECT_NE(upb_ExtensionRegistry_Lookup(
4949
reg_, &upb__test_02023__EditionsMessage_msg_init, 100),
@@ -55,7 +55,7 @@ TEST_F(GeneratedRegistryTest, ForeignExtensionExists) {
5555
// linked in.
5656

5757
// Force linkage and sanity check extension numbers.
58-
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_message_opt_ext), 7739036);
58+
ASSERT_EQ(upb_MiniTableExtension_Number(upb_message_opt_ext), 7739036);
5959

6060
EXPECT_NE(upb_ExtensionRegistry_Lookup(reg_, &google__protobuf__MessageOptions_msg_init,
6161
7739036),
@@ -77,8 +77,8 @@ TEST_F(GeneratedRegistryTest, MultipleFilesExtensionExists) {
7777
// in and registered.
7878

7979
// Force linkage and sanity check extension numbers.
80-
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_multiple_files_ext1_ext), 100);
81-
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_multiple_files_ext2_ext), 100);
80+
ASSERT_EQ(upb_MiniTableExtension_Number(upb_multiple_files_ext1_ext), 100);
81+
ASSERT_EQ(upb_MiniTableExtension_Number(upb_multiple_files_ext2_ext), 100);
8282

8383
EXPECT_NE(upb_ExtensionRegistry_Lookup(
8484
reg_, &upb__MultipleFilesMessage1_msg_init, 100),

0 commit comments

Comments
 (0)