opensourcerouting / c-capnproto

C library/compiler for the Cap'n Proto serialization/RPC protocol
MIT License
118 stars 40 forks source link

Incorrect assumption that a C enum is always 2 octets wipes enum values sometimes. #38

Closed detly closed 3 years ago

detly commented 3 years ago

I have a Cap'n Proto schema that looks like:

struct UI {
    union {
        thing1 @0 :Text;
        thing2 @1 :AnEnumType;
        thing3 @2 :UInt16;
    }
}

The enum type is represented as a C enum. But the generated code treats it as interchangeable with the UInt16 type:

void read_UI(struct UI *s capnp_unused, UI_ptr p) {
    capn_resolve(&p.p);
    capnp_use(s);
    s->which = (enum UI_which)(int) capn_read16(p.p, 0);
    switch (s->which) {
        // ...
    case UI_thing2:
    case UI_thing3:
        s->thing3 = capn_read16(p.p, 2); 

The size of a C enum is not specified by the standard; compilers can choose whatever is appropriate. On my platform this is 4 octets (32 bits), so the LSBs of the enum are wiped. This changes with the positioning of the enum in the Cap'n Proto definition; in an even numbered position, it's fine.