2
\$\begingroup\$

I have an interface under development using an object-based approach. Objects should be statically allocated by the application writer (Dynamic memory allocation is not allowed). I want to obfuscate the object data so the application writer can only access the struct members using the provided methods. So I came to this

typedef struct{ /*this its the object private data*/
   uint32_t Parameter;
   uint8_t Value;
   void *owner
   size_t length;
}__xObject_Private_data_t;

typedef struct{ /*this is the object definition*/
    uint8_t xPrivateData[ sizeof(__xObject_Private_data_t) ]; /*data masked with a raw memory block*/
}xObject_t;

object methods follow this pattern:

void xObject_SetValue( xObject_t *obj, uint8_t newvalue ){
    __xObject_Private_data_t *handler;
    if( NULL != obj ){
        handler = (__xObject_Private_data_t*)obj->xPrivateData;
        handler->Value = newvalue;
    }   
}

I deep analyze this implementation keeping this in mind: - Portability - Data padding and alignment - Strict aliasing rules

So far, I consider that everything meets my requirements, however, I would like to have some final concept in case I am missing something before consolidating my solution.

\$\endgroup\$
  • \$\begingroup\$ Is __xObject_Private_data_t defined in the same header as xObject_t? If so, the application writer can do the same thing you are to get at the data. If not, how do you intend to keep the actual struct and the data block that is supposed to store it from getting out of sync with their sizes? \$\endgroup\$ – 1201ProgramAlarm Jan 26 at 2:42
3
\$\begingroup\$

1201ProgramAlarm rightly comments:

Is __xObject_Private_data_t defined in the same header as xObject_t? If so, the application writer can do the same thing you are to get at the data.

In other words, your chosen approach is no solution at all.

Besides, your chosen approach is buggy! A C data type consists of more than its sizeof. You also have to consider alignment.

struct Bad {
    char pad;
    xObject_t x;
};
struct Good {
    char pad;
    __xObject_Private_data_t x;
};

struct Bad's alignment is 1, which means that after your cast to __xObject_Private_data_t you'll find you're getting a lot of misaligned loads and stores (or, on ARM and PowerPC, plain old bus errors).

You seem to be under the impression that double-underscoring an identifier makes it a "private implementation detail." If you trust your users to follow that convention, then you can use a much simpler solution:

typedef struct {
   uint32_t __Private_parameter;
   uint8_t __Private_value;
   void *__Private_owner;
   size_t __Private_length;
} xObject_t;

(Obligatory note that in both C and C++, technically, it's not valid to use double-underscored names if you're not the compiler vendor. Use a single underscore followed by a lowercase letter — _private0_parameter — and you'll be okay.)

To help ensure that your clients don't go poking at _private0_parameter, you can just change its name to _private1_parameter in your next minor release. And then _prviate2_parameter in the release after that. (Heck, keep the misspelling! That will really ensure that nobody wants to touch those data members.)

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.