5

I have a library that is compiled to use 32 bit signed integer. When other applications compile theirs with a flag e.g: -DODBC64 it promotes the same type I have used in my library to a 64 bit signed integer. e.g:

 #ifdef ODBC64
       typedef sint64 SLEN;
 #else
       #define SLEN int
 #endif

When the application passes reference to my library as :

SLEN count;
mylibraryfunction(&count);

the values returned to application looks like these:

sizeof(SLEN) = 8
sizeof(SLEN) in my library = 4
m_AffectedRows BEFORE = 0x3030303030303030
m_AffectedRows AFTER = 0x3030303000000000        0

You can see that the assignment from my lib is copying 4 bytes (value 0). I need to know a way to reset the upper 4 bytes to 0. e.g:

0x0000000000000000

I have tried both static_cast and reinterpret_cast, but none are helpful.

5
  • 1
    That's very critical. You pass a 64 bit int by address to a function which interpretes it as 32 bit int trusting it's declaration. This works as the linker cannot recognize the distinct type of equal named symbols and may link this without any warning but it's still wrong. Commented Mar 27, 2019 at 8:43
  • That sounds dangerous, indeed. Is there any reason to have 32bit on one side and 64bit on the other? If so, I suggest writing a small wrapper for every function, which just does type conversion (and perhaps checks for overflows). Commented Mar 27, 2019 at 8:52
  • So would I provide 2 different versions of my library. Once for 8 byte usage and one for 4 byte usage from applications that they can link against. Commented Mar 27, 2019 at 8:54
  • It is not clear to me why you need different int-sizes at all. Do you compile for x86-32 and x86-64, or does the 32bit version save significant amount of memory? Commented Mar 27, 2019 at 8:56
  • 2
    This would be why we should use to stdint.h types and not some local garage standard... Commented Mar 27, 2019 at 8:58

2 Answers 2

1

I made a MCVE where I resembled what happens in OPs case.

I even didn't need an extra library for this, just two translation units (resulting in two object files).

First lib.cc:

#include <cstdint>

extern "C" void func(int32_t *pValue);

void func(std::int32_t *pValue)
{
  *pValue = 0;
}

Second prog.cc:

#include <iostream>
#include <iomanip>

// how prog.cc "knows" func():
extern "C" void func(int64_t *pValue);

int main()
{
  int64_t value = 0x0123456789ABCDEFull;
  std::cout << "value before: " << std::hex << value << '\n';
  func(&value);
  std::cout << "value after : " << std::hex << value << '\n';
  return 0;
}

Compiler errors? No. Each translation unit uses prototype of func() conformant.

Linker errors? No. The symbols match, anything else is beyond view of linker.

I must admit I had to use extern "C" to achieve this. Otherwise, at least, the C++ name mangling had prevented the proper linking. (When I became aware of this, I made code in C.)

Output:

value before: 123456789abcdef
value after : 123456700000000

Live Demo on wandbox

This is very dangerous! Any use of any extern symbol should use a 100 % compatible declaration. (And yes, C and C++ provide various ways to shoot into your own foot.)


Imagine what would happen if the lib.cc function func() would write int64_t where the prog.cc would pass a pointer to int32_t: Out of bound access with possible more disastrous consequences.

Sign up to request clarification or add additional context in comments.

5 Comments

This is sort of my thinking. While I can't have users use different obj linkage, I need a way to use them both the 32 bit and 64 variants depending on their application. What I have provided is the simplest form of illustration, but the actual use case requires users to link to library and it should be able to interpret the type correctly.
I don't think single library can handle interpretation to same name of different storage. Hence the reason I thought 2 libs is the solution.
@SabaKauser IMHO, Lundin said it clearly in his comment: For an API, the usage of stdint.h types seems to be more reliable. Btw. even on most 64 bit platforms, an int is 32 bit. Additionally, libraries should always have same platform. Thus, the declaration is the one which should be clean enough to prevent such issues.
@SabaKauser If you need upto 64 bit ints, why not int64_t? This is supported on 32 bit platforms as well. If it cannot be used on 32 bit platforms with more than 32 bits a runtime check could detect accidentally wrong usage.
Thanks. The requirement is that certain driver managers treat the type in question as 32-bit and certain as 64 bit. So the facility should be to let them link to the correct versions of my lib as this decision would need to be made by developer depending on what driver manager they are using.
0

Your library can't access the upper 4 bytes, but you can before you call it. So try to initialize it with 0's first:

SLEN count = 0; // initialize with 0's
mylibraryfunction(&count);

2 Comments

This does not sign-extend, though. To do that, you could assign count = int(count); after calling the library function.
First, that doesn't address the problem of addressing a 64-bit int value as a 32-bit int value. That's wrong no matter how the variable is initialized. Second, the OP is providing a library. How could that library possibly initialize a variable that's in the customer-written code that calls the library?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.