LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Problems with Calling C/C++ DLLs from LabVIEW Returning a value simple struct

Solved!
Go to solution

I have learned and downloaded the examples in the following tutorial.

Calling C/C++ DLLs from LabVIEW - NI Community

 

However, when I runned the "Returning A Value Simple Struct Added.vi" (\LabVIEWWrapper\VIs\AdditionalVIs\), my LabVIEW (2016 32bit) crashed and closed.

 

But the "Returning A Value Complex Struct Added.vi" (\LabVIEWWrapper\VIs\AdditionalVIs\) could be correctly runned in my LabVIEW.

 

Did anyone meet the same problem and are there any solutions?

 

Thanks! 

0 Kudos
Message 1 of 4
(1,362 Views)

Never looked into these examples. It looks partly suspect to me (found some wrong comments within seconds). And yes, the example crashes labview (labview 2021SP1).

 

Rolf wrote some comments to these examples, so further investigation is not needed 🙂 

 

 

0 Kudos
Message 2 of 4
(1,326 Views)
Solution
Accepted by topic author MinweiYang

Looking at the C-code it is not surprising that it crashes:

struct simpleStructCircle
{
	float x;
	float y;
	float radius;
};		

struct simpleStructCircle ReturningAValue_SimpleStruct(void)
{
	struct simpleStructCircle circle = {1, 1, 3};
	return circle;
}

The return value does not fit in a single register. So it may be returned by reference (which is what the calling VI assumes), but the data referred to is located on the stack which is an invalid memory region after the function returns. Now you have undefined behaviour and what happens is up to the implementers. I suppose this may have worked when it was originally written but the implementation has changed. Since it crashes right after the function call and not when the memory is accessed by GetValueByPointer that could be a completely wrong interpretation though 😄

 

ReturningAValue_PointerToComplexStruct explicitly allocates memory so it is stil valid after the function returns. It is never freed, though...

 

Rolf already left a critical response under the code addressing the problems: https://forums.ni.com/t5/Developer-Center-Resources/Calling-C-C-DLLs-Containing-Simple-and-Complex-D...

Message 3 of 4
(1,314 Views)

That code definitely can't work. cordm's analysis is pretty much on the spot for why although the details are a little bit more murky. It almost certainly will crash because the definition of the Call Library Node does not match with the actual stack layout of the function and causes therefore a nasty stack corruption. A return value of a function needs to fit into a single register or is otherwise usually promoted to a reference implicitly and passed through a so called shadow parameter depending on the ABI of your platform. Windows 32-bit and Windows 64-bit have sometimes considerably different rules in respect to such esoteric features. Other ABIs might and actually have in the past chosen to reserve additional registers for oversized return values but sooner or later there simply are not enough registers left and something else needs to be done here anyhow.

 

On Windows 32-bit, for cdecl functions values up to 32-bit are passed back through the EAX register, for values up to 64-bit  EAX:EDX is used and for all other values a shadow parameter is created. On Windows 64-bit the situation is similar except that integer types up to 64-bit size are passed back in RAX, non-integer types up to 128-bit including float and double are passed back in XMM0 and everything else needs to be treated in the same way as for Windows 32-bit with a shadow parameter.

 

The function the compiler will generate for this particular code is actually this:

 

struct simpleStructCircle
{
	float x;
	float y;
	float radius;
};		

struct simpleStructCircle *ReturningAValue_SimpleStruct(simpleStructCircle *circle)
{
	*circle = (simpleStructCircle *){1, 1, 3}; // requires >= C99
	return circle;
}

 

This is simply part of the ABI specification. It can and often will be different for other compilers/platforms! The code in the C source code really looks different than what the C compiler will create but as long as the caller and callee are compiled by a compiler that knows about the specific ABI everything keeps working.

Rolf Kalbermatter
My Blog
Message 4 of 4
(1,207 Views)