4

I don't find anything in Protocol Buffers documentation for exception handling in C++. In Javadoc it has clearly defined ones like InvalidProtocolBufferException, but not in C++.

Sometimes I ran my program and it crashes when it finds missing fields in what it thinks a valid message, then it simply stops and throws errors like this:

[libprotobuf FATAL google/protobuf/message_lite.cc:273] CHECK failed: 
IsInitialized(): Can't serialize message of type "XXX" because it is 
missing required fields: YY, ZZ
unknown file: Failure
C++ exception with description "CHECK failed: IsInitialized(): Can't 
serialize message of type "XXX" because it is missing required fields: 
YY, ZZ" thrown in the test body.

The source code of message_lite.cc all wrapped around with "GOOGLE_DCHECK" or "InitializationErrorMessage"...

My application does not allow exceptions like this to halt the program (not sure what the term is in C++ but basically no UncheckedExceptions), so I really need a way to catch these, log errors, and return gracefully, in case some messages got severely corrupted. Is there anyway doing that? Why do I see this post indicating some sort of google::protobuf::FatalException but I couldn't find documentations around it (only FatalException probably not enough also).

Thanks!

Community
  • 1
  • 1
Superziyi
  • 609
  • 1
  • 9
  • 30

2 Answers2

12

The failure you are seeing indicates that there is a bug in your program -- the program has requested to serialize a message without having filled in all the required fields first. Think of this like a segmentation fault. You shouldn't try to catch this exception -- you should instead fix your app so that the exception never happens in the first place.

Note that the check is a DCHECK, meaning it is only checked in debug builds. In your release builds (when NDEBUG is defined), this check will be skipped and the message will be written even though it is not valid. So, you don't have to worry about this crashing your application in production, only while debugging.

(Technically you could catch google::protobuf::FatalException, but the Protobuf code was not originally designed to be exception-safe. Originally, check failures would simply abort the program. It looks like FatalException was added recently, but since the code is not exception-safe, it's likely that you'll have memory leaks any time a FatalException is thrown. So, you probably should treat it like an abort().)

Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
  • Thanks! One more question though how does Protobuf recognizes itself as whether it's in production mode or DEBUG mode? For my case, is it because I'm using it with Google Test so it automatically figures out it's DEBUG? Sounds fair of the "no exception" deal as I guess this is to made consistent with normal Java vs. C++ conventions? Cos all these "InvalidBufferException" stuff are modeled as exception if it's in Java though, but maybe it's expected, just like you cannot have segfault in Java... – Superziyi Apr 22 '15 at 00:10
  • @Superziyi If you compile protobufs with `NDEBUG` #defined, then it is in release mode, otherwise it is in debug mode (NDEBUG = not debug). If you're on unix and you used the regular configure, make, make install to build protobufs, it should be in release mode by default (you can override by setting `CXXFLAGS` when you run `configure`). If you are on Windows, MSVC typically #defines `NDEBUG` in release configurations. (The NDEBUG macro is a standard C-ism.) – Kenton Varda Apr 24 '15 at 04:39
0

I solved that my problem was same you. if another thread change size of proto item while you do serialization then FatalException throw then at first I copy that in another proto item then I do serialize that.

            ProtoInput item; // it is global object
            . 
            .
            .
            fstream output("myfile",
                    ios::out | ios::trunc | ios::binary);

            ProtoInput in;
            in.CopyFrom(item);
            size_t size = in.ByteSizeLong();
            void *buffer = malloc(size);
            if (in.SerializeToArray(buffer, size) == true) {
                output.write((char *) buffer, size);
            }
            output.close();
            free(buffer);