mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
80 lines
2.8 KiB
C
80 lines
2.8 KiB
C
// 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,
|
|
kUpb_ErrorCode_MaxDepthExceeded = 3,
|
|
} 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__
|