3

Problem:

Recently we've encountered the following problem with our C shared library.
The library defines a method like this one:

typedef enum {A, B, C} some_enum;
typedef struct {some_enum e; time_t t; char* data;} request;
void f(request);

We've compiled the library for multiple architectures using clang and its cross-compilation features. One of the platforms was Windows 32 bits.
And here is the problem: when trying to use the library in an example that uses MSVC 32-bit compiler, the example fails with seg fault.
The reason: in MSVC 32-bit time_t is 8 bytes while in clang compilation for Windows 32-bits it is assumed to be 4 bytes.

Obviously, if we were using fixed-width integer types such as int64_t, this problem would never appear.

Question:

Are there established best practices for primitive types in a portable C shared library?

For instance, is it the best practice to avoid any non fixed-width integer types altogether in C shared library interfaces?
Are for example enums "allowed" (in terms of best practices) in a portable C library?

Alexander
  • 2,761
  • 1
  • 28
  • 33
  • Note that this has nothing to do with compiler: you use two incompatible implementations of standard C runtime library (`time.h` to be specific) for compilation of shared library and application code. – yugr Dec 23 '21 at 14:49
  • @yugr thanks, it's a very useful observation, I've missed it. I think it is still related to a compiler since I'd expect say a compilation done in Linux Arm 64 architecture to be compatible with the default C runtime library available on this system. – Alexander Dec 26 '21 at 14:58
  • This is not always the case e.g. different libc implementations on Linux (Glibc, newlib, musl, etc.) are definitely _not_ compatible. As for your case, could you compile the problematic code with `-E` and check which header file provides `time_t`? (for MSVC you can do this same by "opening" `time.h` in Visual Studio editor. – yugr Dec 26 '21 at 15:36
  • Note: Windows has `__time64_t` and `__time32_t`. The [`_USE_32BIT_TIME_T` macro determines](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/time-time32-time64?view=msvc-170) which one `time_t` is typedefed to. – Yakov Galka Jan 01 '22 at 04:10
  • Thanks @YakovGalka, good to know. – Alexander Jan 02 '22 at 21:11

1 Answers1

2

Typically all compilers for a given platform try very hard to preserve the default C ABI. Violation of ABI is normally considered a compiler bug.

C++ ABI is trickier for various reasons but at least Clang tries hard to preserve that one on Windows as well.

C ABI compatibility means, among other things, that all primitive types have defined size and alignment so there is no need to use fixed-width types (i.e. long will be the same for all compilers for a particular target).

As for your case, I suspect that clang and cl.exe are using different time.h for whatever reason so I suggest to look into that (see my comment above on how to proceed with this).

yugr
  • 19,769
  • 3
  • 51
  • 96