Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/installed_include_golden.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ google/protobuf/wire_format_lite.h
google/protobuf/wrappers.pb.h
google/protobuf/wrappers.proto
upb/base/descriptor_constants.h
upb/base/error_handler.h
upb/base/status.h
upb/base/status.hpp
upb/base/string_view.h
Expand Down
4 changes: 2 additions & 2 deletions rust/upb/sys/wire/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub enum EncodeStatus {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum DecodeStatus {
Ok = 0,
Malformed = 1,
OutOfMemory = 2,
OutOfMemory = 1,
Malformed = 2,
BadUtf8 = 3,
MaxDepthExceeded = 4,
MissingRequired = 5,
Expand Down
1 change: 1 addition & 0 deletions upb/base/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cc_library(
],
hdrs = [
"descriptor_constants.h",
"error_handler.h",
"status.h",
"status.hpp",
"string_view.h",
Expand Down
79 changes: 79 additions & 0 deletions upb/base/error_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google LLC. 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

#ifndef GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__
#define GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__

#include <setjmp.h>

// Must be last.
#include "upb/port/def.inc"

// upb_ErrorHandler is a standard longjmp()-based exception handler for UPB.
// It is used for efficient error handling in cases where longjmp() is safe to
// use, such as in highly performance-sensitive C parsing code.
//
// This structure contains both a jmp_buf and an error code; the error code is
// stored in the structure prior to calling longjmp(). This is necessary because
// per the C standard, it is not possible to store the result of setjmp(), so
// the error code must be passed out-of-band.
//
// upb_ErrorHandler is generally not C++-compatible, because longjmp() does not
// run C++ destructors. So any library that supports upb_ErrorHandler should
// also support a regular return-based error handling mechanism. (Note: we
// could conceivably extend this to take a callback, which could either call
// longjmp() or throw a C++ exception. But since C++ exceptions are forbidden
// by the C++ style guide, there's not likely to be a demand for this.)
//
// To support both cases (longjmp() or return-based status) efficiently, code
// can be written like this:
//
// UPB_ATTR_CONST bool upb_Arena_HasErrHandler(const upb_Arena* a);
//
// INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) {
// if (UPB_UNLIKELY(a->end - a->ptr < size)) {
// void* ret = upb_Arena_MallocFallback(a, size);
// UPB_MAYBE_ASSUME(upb_Arena_HasErrHandler(a), ret != NULL);
// return ret;
// }
// void* ret = a->ptr;
// a->ptr += size;
// UPB_ASSUME(ret != NULL);
// return ret;
// }
//
// If the optimizer can prove that an error handler is present, it can assume
// that upb_Arena_Malloc() will not return NULL.

// We need to standardize on any error code that might be thrown by an error
// handler.

typedef enum {
kUpb_ErrorCode_Ok = 0,
kUpb_ErrorCode_OutOfMemory = 1,
kUpb_ErrorCode_Malformed = 2,
} upb_ErrorCode;

typedef struct {
int code;
jmp_buf buf;
} upb_ErrorHandler;

UPB_INLINE void upb_ErrorHandler_Init(upb_ErrorHandler* e) {
e->code = kUpb_ErrorCode_Ok;
}

UPB_INLINE UPB_NORETURN void upb_ErrorHandler_ThrowError(upb_ErrorHandler* e,
int code) {
UPB_ASSERT(code != kUpb_ErrorCode_Ok);
e->code = code;
UPB_LONGJMP(e->buf, 1);
}

#include "upb/port/undef.inc"

#endif // GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__
9 changes: 9 additions & 0 deletions upb/port/def.inc
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,15 @@ Error, UINTPTR_MAX is undefined
#define UPB_ASSUME(expr) assert(expr)
#endif

#if UPB_HAS_BUILTIN(__builtin_constant_p) && UPB_HAS_ATTRIBUTE(const)
#define UPB_MAYBE_ASSUME(pred, x) \
if (__builtin_constant_p(pred) && pred) UPB_ASSUME(x)
#define UPB_ATTR_CONST __attribute__((const))
#else
#define UPB_MAYBE_ASSUME(pred, x)
#define UPB_ATTR_CONST
#endif

/* UPB_ASSERT(): in release mode, we use the expression without letting it be
* evaluated. This prevents "unused variable" warnings. */
#ifdef NDEBUG
Expand Down
2 changes: 2 additions & 0 deletions upb/port/undef.inc
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,5 @@
#undef UPB_ARM64_ASM
#undef UPB_ARM64_BTI_DEFAULT
#undef UPB_DEPRECATE_AND_INLINE
#undef UPB_MAYBE_ASSUME
#undef UPB_ATTR_CONST
Loading
Loading