01-04-2010 03:54 PM
When a TaskHandle, initialized on the stack, goes out of scope, I get a "Run-Time Check Failure #2 - Stack around the variable was corrupted" message while debugging in Visual Studio. This only happens when I am compiling for 64-bit, not when I am compiling for 32-bit. I am using NI-DAQmx 9.0.2. Has anyone else seen this issue?
01-04-2010 06:13 PM
Hi KKRand,
TaskHandle is just a typedef for void*, so something else is causing the buffer overflow that you're seeing. What does your program do? What DAQmx functions does it call? Does it manipulate any arrays or C strings (either directly, or by calling DAQmx functions)? Could you post a code snippet that demonstrates the problem?
Brad
01-04-2010 06:54 PM
Hi Brad,
You're absolutely right...this must be a sign of array overruns elsewhere. Let me do some more digging, as it may have nothing to do with DAQmx whatsoever. If I do narrow it down to something DAQmx specific, I'll post. Thanks for your help!
01-06-2010 07:57 PM
Actually, it looks like it may be DAQmx related after all.
The nidaqmx.h header file has the following code:
#ifdef kCC32buildingOn_win64U
typedef uInt64 TaskHandle;
typedef uInt64 CalHandle;
#else
typedef uInt32 TaskHandle;
typedef uInt32 CalHandle;
#endif
I am not sure where kCC32buildingOn_win64U would be set, or even what it means (it certainly doesn't come up in any searches in the Developer Zone), but if I redefine TaskHandle to be a uInt64, I no longer see the problem.
If I'm building for a 64-bit target it does seem that I should be using a 64-bit TaskHandle. Is that correct?
Thanks!
01-06-2010 09:07 PM
Hi KKRand,
Aha, that explains what's going on. In your application, there's a mismatch between the function prototype for DAQmxCreateTask() and the actual function implementation in nicaiu.dll. Your application allocates 4 bytes for a task handle, but then DAQmxCreateTask() writes 8 bytes. Stack corruption ensues.
Why is there a mismatch, and what's with that #ifdef? NI-DAQmx 8.9 was the first version to support 64-bit ANSI C applications. In the NIDAQmx.h from 8.9 and later, TaskHandle is a typedef for void*. In 8.8, NIDAQmx.h contained "#ifdef kCC32buildingOn_win64U", which is never defined, but it didn't matter at the time because NI-DAQmx didn't support 64-bit applications yet. Before 8.8, TaskHandle was a typedef for uInt32. If you try to build a 64-bit application using the NIDAQmx.h from 8.8 or before, the size of TaskHandle will not match between DAQmxCreateTask() and the rest of your application.
(Aside: if you keep using the 8.8 NIDAQmx and just #define kCC32buildingOn_win64U to work around the problem, then the size of CalHandle won't match. For 64-bit, we only ended up promoting the size of TaskHandle, not CalHandle.)
It sounds like you copied the new 64-bit nidaqmx.lib into your build environment, but you didn't copy NIDAQmx.h at the same time. Updating NIDAQmx.h and doing a clean rebuild of your app should resolve the problem. I recommend always keeping NIDAQmx.h and nidaqmx.lib in sync: when you update one, update the other as well.
Brad
01-06-2010 11:51 PM
Thanks, Brad. It makes perfect sense now. I am dynamically loading the functions, but was indeed using a template based on 8.8.
This does make me realize that I need to make sure any user has 8.9 (or later) installed. Is the best way to do this programmatically querying the registry for the CurrentVersion value? I couldn't find a C function that returned the active version of the library.
Thanks again.
01-07-2010 11:18 AM - edited 01-07-2010 11:18 AM
Hi KKRand,
Changing TaskHandle from uInt32 to void* did not break binary compatibility for 32-bit apps. 64-bit apps will get an error from LoadLibrary("nicaiu.dll") when run on DAQmx <8.9. And if you use newer functions that don't exist on the user's older version of DAQmx, GetProcAddress() will error. So you might not need to check the version number, as long as you're checking the return values of LoadLibrary() and GetProcAddress() (or the equivalent for your programming environment).
Anyway, here are the C functions to get the DAQmx version:
int32 __CFUNC DAQmxGetSysNIDAQMajorVersion(uInt32 *data);
int32 __CFUNC DAQmxGetSysNIDAQMinorVersion(uInt32 *data);
int32 __CFUNC DAQmxGetSysNIDAQUpdateVersion(uInt32 *data);
Brad
01-07-2010 01:00 PM - edited 01-07-2010 01:02 PM