protocolbuffers/protobuf

C++ | Array size of enumeration not reliable in case of not consecutive numbers (actual size does not match)

Open

#15,541 opened on 2024年1月23日

GitHub で見る
 (4 comments) (0 reactions) (0 assignees)C++ (16,128 forks)batch import
c++help wanted

Repository metrics

Stars
 (71,223 stars)
PR merge metrics
 (平均マージ 2d 11h) (30d で 185 merged PRs)

説明

I have found this issue working on gRPC project, and reported here https://github.com/grpc/grpc/issues/35577. It turns out that is is actually an issue on the underlying protobuf, so I am reporting here.

What version of gRPC and what language are you using?

grpc-1.51.0

What operating system (Linux, Windows,...) and version?

Linux

What runtime / compiler are you using (e.g. python version or version of gcc)

clang-16

What did you do?

Generate C++ code from a pro to containing enumeration (note that 5 is missing)

message Footprint {
  int64 id = 1;
  enum ConfigType {
    UNKNOWN_CONFIG_TYPE = 0;
    FP_100 = 1;
    FP_250 = 2;
    FP_500 = 3;
    FP_1000 = 4;
    FP_2000 = 6;
  }
// Other stuff here
}

What did you expect to see?

Generated code.

/*...*/
enum Footprint_ConfigType : int {
  Footprint_ConfigType_UNKNOWN_CONFIG_TYPE = 0,
  Footprint_ConfigType_FP_100 = 1,
  Footprint_ConfigType_FP_250 = 2,
  Footprint_ConfigType_FP_500 = 3,
  Footprint_ConfigType_FP_1000 = 4,
  Footprint_ConfigType_FP_2000 = 6,
  Footprint_ConfigType_Footprint_ConfigType_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
  Footprint_ConfigType_Footprint_ConfigType_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
};
bool Footprint_ConfigType_IsValid(int value);
constexpr Footprint_ConfigType Footprint_ConfigType_ConfigType_MIN = Footprint_ConfigType_UNKNOWN_CONFIG_TYPE;
constexpr Footprint_ConfigType Footprint_ConfigType_ConfigType_MAX = Footprint_ConfigType_FP_2000;
constexpr int Footprint_ConfigType_ConfigType_ARRAYSIZE = 6;
/*...*/

The Footprint_ConfigType_ConfigType_ARRAYSIZE constant is set to the actual number of items in the enumeration (6 in this case)

What did you see instead?

Generated code:

/*...*/
enum Footprint_ConfigType : int {
  Footprint_ConfigType_UNKNOWN_CONFIG_TYPE = 0,
  Footprint_ConfigType_FP_100 = 1,
  Footprint_ConfigType_FP_250 = 2,
  Footprint_ConfigType_FP_500 = 3,
  Footprint_ConfigType_FP_1000 = 4,
  Footprint_ConfigType_FP_2000 = 6,
  Footprint_ConfigType_Footprint_ConfigType_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(),
  Footprint_ConfigType_Footprint_ConfigType_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max()
};
bool Footprint_ConfigType_IsValid(int value);
constexpr Footprint_ConfigType Footprint_ConfigType_ConfigType_MIN = Footprint_ConfigType_UNKNOWN_CONFIG_TYPE;
constexpr Footprint_ConfigType Footprint_ConfigType_ConfigType_MAX = Footprint_ConfigType_FP_2000;
constexpr int Footprint_ConfigType_ConfigType_ARRAYSIZE = Footprint_ConfigType_ConfigType_MAX + 1;
/*...*/

The Footprint_ConfigType_ConfigType_ARRAYSIZE constant is set to Footprint_ConfigType_ConfigType_MAX + 1 that become 7 in this case because item 5 is missing. As it is, the Footprint_ConfigType_ConfigType_ARRAYSIZE is not reliable and cannot be used as boundary check in for loops.

Workaround: Need to take a separate counter for the actual number element in the enumeration.

Anything else we should know about your project / environment?

Nothing to add

コントリビューターガイド