Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing a C API to your C++ library and strict aliasing

Tags:

A common pattern when providing a C API is to forward declare some opaque types in your public header which are passed to your API methods and then reinterpret_cast them into your defined C++ types once inside the translation unit (and therefore back in C++ land).

Using LLVM as an example:

In Types.h this typedef is declared:

typedef struct LLVMOpaqueContext *LLVMContextRef; 

LLVMOpaqueContext is not referenced anywhere else in the project.

In Core.h the following method is declared:

LLVMContextRef LLVMContextCreate(void); 

Which is defined in Core.cpp:

LLVMContextRef LLVMContextCreate() {   return wrap(new LLVMContext()); } 

wrap (and unwrap) is defined by a macro in CBindingWrapping.h:

#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)     \   inline ty *unwrap(ref P) {                            \     return reinterpret_cast<ty*>(P);                    \   }                                                     \                                                         \   inline ref wrap(const ty *P) {                        \     return reinterpret_cast<ref>(const_cast<ty*>(P));   \ } 

And used in LLVMContext.h:

DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef) 

So we see that the C API basically takes a pointer to an LLVMOpaqueContext and casts it into an llvm::LLVMContext object to perform whatever method is called on it.

My question is: isn't this in violation of the strict aliasing rules? If not, why not? And if so, how can this type of abstraction at the public interface boundary be acheived legally?

like image 251
Sam Kellett Avatar asked Mar 12 '18 11:03

Sam Kellett


People also ask

Is there aliasing in C?

In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.

What is pointer aliasing in C?

Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.


1 Answers

It's not a strict aliasing violation. To start with, strict aliasing is about accessing an object via a glvalue of the wrong type.

In your question, you create a LLVMContext, and then use a LLVMContext lvalue to access it. No illegal aliasing there.

The only issue which may arise is if the the pointer conversion doesn't yield back the same pointer. But that too is not a problem, since reinterpret_cast is guaranteed to give back the same pointer in a round-trip conversion. So long as the pointer type we convert to and back from is to suitably aligned data (i.e. not stricter than the original type).

Whether or not it's a good or bad way to go about things is debatable. I personally would not bother with LLVMOpaqueContext and return a struct LLVMContext*. It's still an opaque pointer, and it doesn't matter that the C header declares it with struct while the type definition is with class. The two are interchangeable up to the point of the type definition.

like image 124
StoryTeller - Unslander Monica Avatar answered Oct 17 '22 16:10

StoryTeller - Unslander Monica