From 3c50c0da0e861c507c632bd757e035aa2798248c Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Thu, 6 Mar 2025 21:18:27 +0000 Subject: [PATCH] Auto-generate files after cl/734258255 --- php/ext/google/protobuf/php-upb.c | 78 ++++++++++++++++++++++++--- php/ext/google/protobuf/php-upb.h | 57 ++++++++++++++++++-- ruby/ext/google/protobuf_c/ruby-upb.c | 78 ++++++++++++++++++++++++--- ruby/ext/google/protobuf_c/ruby-upb.h | 57 ++++++++++++++++++-- 4 files changed, 248 insertions(+), 22 deletions(-) diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 196d1eeda2..a50b7d0dac 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -4262,17 +4262,38 @@ bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, size_t len, upb_Arena* arena, bool alias) { UPB_ASSERT(!upb_Message_IsFrozen(msg)); - if (alias) { - // Fast path if the field we're adding is immediately after the last added - // unknown field. + { upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in && in->size) { upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; if (upb_TaggedAuxPtr_IsUnknown(ptr)) { upb_StringView* existing = upb_TaggedAuxPtr_UnknownData(ptr); - if (existing->data + existing->size == data) { - existing->size += len; - return true; + bool was_aliased = upb_TaggedAuxPtr_IsUnknownAliased(ptr); + if (alias) { + // Fast path if the field we're adding is immediately after the last + // added unknown field. + if (was_aliased && existing->data + existing->size == data) { + existing->size += len; + return true; + } + } else if (!was_aliased) { + // If part of the existing field was deleted at the beginning, we can + // reconstruct it by comparing the address of the end with the address + // of the entry itself; having the non-aliased tag means that the + // string_view and the data it points to are part of the same original + // upb_Arena_Malloc allocation, and the end of the string view + // represents the end of that allocation. + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= len) { + size_t new_alloc_size = prev_alloc_size + len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + memcpy(UPB_PTR_AT(existing, prev_alloc_size, void), data, len); + existing->size += len; + return true; + } + } } } } @@ -4297,7 +4318,9 @@ bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, } view->size = len; upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); - in->aux_data[in->size++] = upb_TaggedAuxPtr_MakeUnknownData(view); + in->aux_data[in->size++] = alias + ? upb_TaggedAuxPtr_MakeUnknownDataAliased(view) + : upb_TaggedAuxPtr_MakeUnknownData(view); return true; } @@ -4309,8 +4332,40 @@ bool UPB_PRIVATE(_upb_Message_AddUnknownV)(struct upb_Message* msg, UPB_ASSERT(count > 0); size_t total_len = 0; for (size_t i = 0; i < count; i++) { + if (SIZE_MAX - total_len < data[i].size) { + return false; + } total_len += data[i].size; } + + { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in && in->size) { + upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; + if (upb_TaggedAuxPtr_IsUnknown(ptr)) { + upb_StringView* existing = upb_TaggedAuxPtr_UnknownData(ptr); + if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= total_len) { + size_t new_alloc_size = prev_alloc_size + total_len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + char* copy = UPB_PTR_AT(existing, prev_alloc_size, char); + for (size_t i = 0; i < count; i++) { + memcpy(copy, data[i].data, data[i].size); + copy += data[i].size; + } + existing->size += total_len; + return true; + } + } + } + } + } + } + + if (SIZE_MAX - sizeof(upb_StringView) < total_len) return false; if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) return false; upb_StringView* view = @@ -4368,6 +4423,10 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg, } else if (unknown->data + unknown->size == data->data + data->size) { // Truncate existing field unknown->size -= data->size; + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = + upb_TaggedAuxPtr_MakeUnknownDataAliased(unknown); + } } else { UPB_ASSERT(unknown->data < data->data && unknown->data + unknown->size > data->data + data->size); @@ -4386,7 +4445,10 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg, memmove(&in->aux_data[*iter + 1], &in->aux_data[*iter], sizeof(upb_TaggedAuxPtr) * (in->size - *iter)); } - in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownData(suffix); + in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownDataAliased(suffix); + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = upb_TaggedAuxPtr_MakeUnknownDataAliased(prefix); + } in->size++; suffix->data = data->data + data->size; suffix->size = (prefix->data + prefix->size) - suffix->data; diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 69c9429709..b343ede82a 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -789,7 +789,28 @@ UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr, UPB_ASSERT(_upb_Arena_WasLastAlloc(a, ptr, oldsize)); #endif } - UPB_POISON_MEMORY_REGION((char*)ptr + size, oldsize - size); + UPB_POISON_MEMORY_REGION((char*)ptr + (size - UPB_ASAN_GUARD_SIZE), + oldsize - size); +} + +UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + UPB_TSAN_CHECK_WRITE(a->UPB_ONLYBITS(ptr)); + UPB_ASSERT(size > oldsize); + size = UPB_ALIGN_MALLOC(size) + UPB_ASAN_GUARD_SIZE; + oldsize = UPB_ALIGN_MALLOC(oldsize) + UPB_ASAN_GUARD_SIZE; + if (size == oldsize) { + return true; + } + size_t extend = size - oldsize; + if ((char*)ptr + oldsize == a->UPB_ONLYBITS(ptr) && + UPB_PRIVATE(_upb_ArenaHas)(a) >= extend) { + a->UPB_ONLYBITS(ptr) += extend; + UPB_UNPOISON_MEMORY_REGION((char*)ptr + (oldsize - UPB_ASAN_GUARD_SIZE), + extend); + return true; + } + return false; } #ifdef __cplusplus @@ -881,6 +902,16 @@ void upb_Arena_SetMaxBlockSize(size_t max); UPB_API_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, size_t size); +// Attempts to extend the given alloc from arena, in place. Is generally +// only likely to succeed for the most recent allocation from this arena. If it +// succeeds, returns true and `ptr`'s allocation is now `size` rather than +// `oldsize`. Returns false if the allocation cannot be extended; `ptr`'s +// allocation is unmodified. See also upb_Arena_Realloc. +// REQUIRES: `size > oldsize`; to shrink, use `upb_Arena_Realloc` or +// `upb_Arena_ShrinkLast`. +UPB_API_INLINE bool upb_Arena_TryExtend(upb_Arena* a, void* ptr, size_t oldsize, + size_t size); + #ifdef UPB_TRACING_ENABLED void upb_Arena_SetTraceHandler(void (*initArenaTraceHandler)(const upb_Arena*, size_t size), @@ -3315,6 +3346,10 @@ extern const double kUpb_NaN; // extensions. We can change this without breaking binary compatibility. typedef struct upb_TaggedAuxPtr { + // Two lowest bits form a tag: + // 00 - non-aliased unknown data + // 10 - aliased unknown data + // 01 - extension uintptr_t ptr; } upb_TaggedAuxPtr; @@ -3330,14 +3365,18 @@ UPB_INLINE bool upb_TaggedAuxPtr_IsUnknown(upb_TaggedAuxPtr ptr) { return (ptr.ptr != 0) && ((ptr.ptr & 1) == 0); } +UPB_INLINE bool upb_TaggedAuxPtr_IsUnknownAliased(upb_TaggedAuxPtr ptr) { + return (ptr.ptr != 0) && ((ptr.ptr & 2) == 2); +} + UPB_INLINE upb_Extension* upb_TaggedAuxPtr_Extension(upb_TaggedAuxPtr ptr) { UPB_ASSERT(upb_TaggedAuxPtr_IsExtension(ptr)); - return (upb_Extension*)(ptr.ptr & ~1ULL); + return (upb_Extension*)(ptr.ptr & ~3ULL); } UPB_INLINE upb_StringView* upb_TaggedAuxPtr_UnknownData(upb_TaggedAuxPtr ptr) { UPB_ASSERT(!upb_TaggedAuxPtr_IsExtension(ptr)); - return (upb_StringView*)(ptr.ptr); + return (upb_StringView*)(ptr.ptr & ~3ULL); } UPB_INLINE upb_TaggedAuxPtr upb_TaggedAuxPtr_Null(void) { @@ -3353,6 +3392,9 @@ upb_TaggedAuxPtr_MakeExtension(const upb_Extension* e) { return ptr; } +// This tag means that the original allocation for this field starts with the +// string view and ends with the end of the content referenced by the string +// view. UPB_INLINE upb_TaggedAuxPtr upb_TaggedAuxPtr_MakeUnknownData(const upb_StringView* sv) { upb_TaggedAuxPtr ptr; @@ -3360,6 +3402,15 @@ upb_TaggedAuxPtr_MakeUnknownData(const upb_StringView* sv) { return ptr; } +// This tag implies no guarantee between the relationship of the string view and +// the data it points to. +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeUnknownDataAliased(const upb_StringView* sv) { + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)sv | 2; + return ptr; +} + typedef struct upb_Message_Internal { // Total number of entries set in aux_data uint32_t size; diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 757b9c574e..560da3cd07 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -4262,17 +4262,38 @@ bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, size_t len, upb_Arena* arena, bool alias) { UPB_ASSERT(!upb_Message_IsFrozen(msg)); - if (alias) { - // Fast path if the field we're adding is immediately after the last added - // unknown field. + { upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); if (in && in->size) { upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; if (upb_TaggedAuxPtr_IsUnknown(ptr)) { upb_StringView* existing = upb_TaggedAuxPtr_UnknownData(ptr); - if (existing->data + existing->size == data) { - existing->size += len; - return true; + bool was_aliased = upb_TaggedAuxPtr_IsUnknownAliased(ptr); + if (alias) { + // Fast path if the field we're adding is immediately after the last + // added unknown field. + if (was_aliased && existing->data + existing->size == data) { + existing->size += len; + return true; + } + } else if (!was_aliased) { + // If part of the existing field was deleted at the beginning, we can + // reconstruct it by comparing the address of the end with the address + // of the entry itself; having the non-aliased tag means that the + // string_view and the data it points to are part of the same original + // upb_Arena_Malloc allocation, and the end of the string view + // represents the end of that allocation. + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= len) { + size_t new_alloc_size = prev_alloc_size + len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + memcpy(UPB_PTR_AT(existing, prev_alloc_size, void), data, len); + existing->size += len; + return true; + } + } } } } @@ -4297,7 +4318,9 @@ bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, } view->size = len; upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); - in->aux_data[in->size++] = upb_TaggedAuxPtr_MakeUnknownData(view); + in->aux_data[in->size++] = alias + ? upb_TaggedAuxPtr_MakeUnknownDataAliased(view) + : upb_TaggedAuxPtr_MakeUnknownData(view); return true; } @@ -4309,8 +4332,40 @@ bool UPB_PRIVATE(_upb_Message_AddUnknownV)(struct upb_Message* msg, UPB_ASSERT(count > 0); size_t total_len = 0; for (size_t i = 0; i < count; i++) { + if (SIZE_MAX - total_len < data[i].size) { + return false; + } total_len += data[i].size; } + + { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in && in->size) { + upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; + if (upb_TaggedAuxPtr_IsUnknown(ptr)) { + upb_StringView* existing = upb_TaggedAuxPtr_UnknownData(ptr); + if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= total_len) { + size_t new_alloc_size = prev_alloc_size + total_len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + char* copy = UPB_PTR_AT(existing, prev_alloc_size, char); + for (size_t i = 0; i < count; i++) { + memcpy(copy, data[i].data, data[i].size); + copy += data[i].size; + } + existing->size += total_len; + return true; + } + } + } + } + } + } + + if (SIZE_MAX - sizeof(upb_StringView) < total_len) return false; if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) return false; upb_StringView* view = @@ -4368,6 +4423,10 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg, } else if (unknown->data + unknown->size == data->data + data->size) { // Truncate existing field unknown->size -= data->size; + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = + upb_TaggedAuxPtr_MakeUnknownDataAliased(unknown); + } } else { UPB_ASSERT(unknown->data < data->data && unknown->data + unknown->size > data->data + data->size); @@ -4386,7 +4445,10 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg, memmove(&in->aux_data[*iter + 1], &in->aux_data[*iter], sizeof(upb_TaggedAuxPtr) * (in->size - *iter)); } - in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownData(suffix); + in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownDataAliased(suffix); + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = upb_TaggedAuxPtr_MakeUnknownDataAliased(prefix); + } in->size++; suffix->data = data->data + data->size; suffix->size = (prefix->data + prefix->size) - suffix->data; diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 9d63a37d14..6a26c0729f 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -791,7 +791,28 @@ UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr, UPB_ASSERT(_upb_Arena_WasLastAlloc(a, ptr, oldsize)); #endif } - UPB_POISON_MEMORY_REGION((char*)ptr + size, oldsize - size); + UPB_POISON_MEMORY_REGION((char*)ptr + (size - UPB_ASAN_GUARD_SIZE), + oldsize - size); +} + +UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + UPB_TSAN_CHECK_WRITE(a->UPB_ONLYBITS(ptr)); + UPB_ASSERT(size > oldsize); + size = UPB_ALIGN_MALLOC(size) + UPB_ASAN_GUARD_SIZE; + oldsize = UPB_ALIGN_MALLOC(oldsize) + UPB_ASAN_GUARD_SIZE; + if (size == oldsize) { + return true; + } + size_t extend = size - oldsize; + if ((char*)ptr + oldsize == a->UPB_ONLYBITS(ptr) && + UPB_PRIVATE(_upb_ArenaHas)(a) >= extend) { + a->UPB_ONLYBITS(ptr) += extend; + UPB_UNPOISON_MEMORY_REGION((char*)ptr + (oldsize - UPB_ASAN_GUARD_SIZE), + extend); + return true; + } + return false; } #ifdef __cplusplus @@ -883,6 +904,16 @@ void upb_Arena_SetMaxBlockSize(size_t max); UPB_API_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, size_t size); +// Attempts to extend the given alloc from arena, in place. Is generally +// only likely to succeed for the most recent allocation from this arena. If it +// succeeds, returns true and `ptr`'s allocation is now `size` rather than +// `oldsize`. Returns false if the allocation cannot be extended; `ptr`'s +// allocation is unmodified. See also upb_Arena_Realloc. +// REQUIRES: `size > oldsize`; to shrink, use `upb_Arena_Realloc` or +// `upb_Arena_ShrinkLast`. +UPB_API_INLINE bool upb_Arena_TryExtend(upb_Arena* a, void* ptr, size_t oldsize, + size_t size); + #ifdef UPB_TRACING_ENABLED void upb_Arena_SetTraceHandler(void (*initArenaTraceHandler)(const upb_Arena*, size_t size), @@ -3317,6 +3348,10 @@ extern const double kUpb_NaN; // extensions. We can change this without breaking binary compatibility. typedef struct upb_TaggedAuxPtr { + // Two lowest bits form a tag: + // 00 - non-aliased unknown data + // 10 - aliased unknown data + // 01 - extension uintptr_t ptr; } upb_TaggedAuxPtr; @@ -3332,14 +3367,18 @@ UPB_INLINE bool upb_TaggedAuxPtr_IsUnknown(upb_TaggedAuxPtr ptr) { return (ptr.ptr != 0) && ((ptr.ptr & 1) == 0); } +UPB_INLINE bool upb_TaggedAuxPtr_IsUnknownAliased(upb_TaggedAuxPtr ptr) { + return (ptr.ptr != 0) && ((ptr.ptr & 2) == 2); +} + UPB_INLINE upb_Extension* upb_TaggedAuxPtr_Extension(upb_TaggedAuxPtr ptr) { UPB_ASSERT(upb_TaggedAuxPtr_IsExtension(ptr)); - return (upb_Extension*)(ptr.ptr & ~1ULL); + return (upb_Extension*)(ptr.ptr & ~3ULL); } UPB_INLINE upb_StringView* upb_TaggedAuxPtr_UnknownData(upb_TaggedAuxPtr ptr) { UPB_ASSERT(!upb_TaggedAuxPtr_IsExtension(ptr)); - return (upb_StringView*)(ptr.ptr); + return (upb_StringView*)(ptr.ptr & ~3ULL); } UPB_INLINE upb_TaggedAuxPtr upb_TaggedAuxPtr_Null(void) { @@ -3355,6 +3394,9 @@ upb_TaggedAuxPtr_MakeExtension(const upb_Extension* e) { return ptr; } +// This tag means that the original allocation for this field starts with the +// string view and ends with the end of the content referenced by the string +// view. UPB_INLINE upb_TaggedAuxPtr upb_TaggedAuxPtr_MakeUnknownData(const upb_StringView* sv) { upb_TaggedAuxPtr ptr; @@ -3362,6 +3404,15 @@ upb_TaggedAuxPtr_MakeUnknownData(const upb_StringView* sv) { return ptr; } +// This tag implies no guarantee between the relationship of the string view and +// the data it points to. +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeUnknownDataAliased(const upb_StringView* sv) { + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)sv | 2; + return ptr; +} + typedef struct upb_Message_Internal { // Total number of entries set in aux_data uint32_t size;