03-08-2016 03:08 AM
The osiUserCode.cpp supplied by NI invokes undefined behaviour for 64bit builds, since it uses 32bit integers (4 bytes) to store addresses (8 bytes) returned by viGetAttribute and the likes, resulting in stack corruption.
I don't know how and who to contact at NI to get this fixed so I'm posting a workaround here; fix is just using size_t for storage, and a checked cast when the address needs converting to 32bit.
/* * VISA/osiUserCode.cpp (for VISA) * osiUserCode.cpp holds the two user defined functions needed to port iBus * to a target platform. * * iBus* acquireBoard(char*brdLocation) -- constructs and initializes the iBus * void releaseBoard(iBus *&bus) -- deletes and cleans up the iBus * * Copyright 2011 National Instruments * License: NATIONAL INSTRUMENTS SOFTWARE LICENSE AGREEMENT * Refer to "MHDDK License Agreement.pdf" in the root of this distribution. * */ #include <limits> #include <stdexcept> #include <cassert> // Platform independent headers #include "osiBus.h" // VISA specific headers #define NIVISA_PXI #include "visa.h" #ifdef _WIN64 u32 adress_cast( size_t p ) { static_assert( sizeof( u32 ) < sizeof( size_t ), "incorrect size_t size" ); if( p > std::numeric_limits< u32 >::max() ) { const auto message = "cannot safely cast 64bit address to 32bit address"; assert( 0 && message ); throw std::runtime_error( message ); } return static_cast< u32 >( p ); } #else u32 adress_cast( size_t p ) { static_assert( sizeof( u32 ) == sizeof( size_t ), "incorrect size_t size" ); return p; } #endif struct tVisaSpecific { ViSession sesn; ViSession vi1; #ifndef kBAR0Only ViSession vi2; #endif }; iBus* acquireBoard( tChar* brdLocation ) { iBus* bus; size_t devBAR0; size_t BAR0sz; void* mem0; #ifndef kBAR0Only u32 devBAR1; u32 BAR1sz; void* mem1; #endif ViSession sesn; ViSession vi1; #ifndef kBAR0Only ViSession vi2; #endif ViStatus status; ViUInt32 openTimeout = 1000; // msec ViAccessMode accessMode = VI_NULL; status = viOpenDefaultRM( &sesn ); if( status < 0 ) { return 0; } status = viOpen( sesn, brdLocation, accessMode, openTimeout, &vi1 ); if( status < 0 ) { return 0; } // Extract physical BARs for card status = viGetAttribute( vi1, VI_ATTR_PXI_MEM_BASE_BAR0, &devBAR0 ); status = viGetAttribute( vi1, VI_ATTR_PXI_MEM_SIZE_BAR0, &BAR0sz ); // Memory map the PCI card status = viMapAddress( vi1, VI_PXI_BAR0_SPACE, 0, BAR0sz, 0, 0, &mem0 ); if( status < 0 ) { return 0; } #ifndef kBAR0Only status = viGetAttribute( vi1, VI_ATTR_PXI_MEM_BASE_BAR1, &devBAR1 ); status = viGetAttribute( vi1, VI_ATTR_PXI_MEM_SIZE_BAR1, &BAR1sz ); // VISA only allows one mmap for each session, so we // open the resource a second time to get to BAR1 status = viOpen( sesn, brdLocation, accessMode, openTimeout, &vi2 ); status = viMapAddress( vi2, VI_PXI_BAR1_SPACE, 0, BAR1sz, 0, 0, &mem1 ); if( status < 0 ) { return 0; } #endif // Create a new iBus #ifndef kBAR0Only bus = new iBus( 0, 0, mem0, mem1 ); #else bus = new iBus( 0, 0, mem0, NULL ); #endif bus->_physBar[ 0 ] = adress_cast( devBAR0 ); #ifndef kBAR0Only bus->_physBar[ 1 ] = adress_cast( devBAR1 ); #else bus->_physBar[ 1 ] = 0; #endif bus->_physBar[ 2 ] = 0; bus->_physBar[ 3 ] = 0; bus->_physBar[ 4 ] = 0; bus->_physBar[ 5 ] = 0; tVisaSpecific* specific = new tVisaSpecific; specific->sesn = sesn; specific->vi1 = vi1; #ifndef kBAR0Only specific->vi2 = vi2; #endif bus->_osSpecific = reinterpret_cast< void* >( specific ); return bus; } void releaseBoard( iBus*& bus ) { tVisaSpecific* specific = reinterpret_cast< tVisaSpecific* >( bus->_osSpecific ); #ifndef kBAR0Only viUnmapAddress( specific->vi2 ); #endif viUnmapAddress( specific->vi1 ); viClose( specific->vi1 ); #ifndef kBAR0Only viClose( specific->vi2 ); #endif viClose( specific->sesn ); delete specific; delete bus; } // // DMA Memory support // class tVISADMAMemory : public tDMAMemory { public: tVISADMAMemory( void* vAddress, size_t pAddress, u32 size, ViSession vi ) : tDMAMemory( vAddress, adress_cast( pAddress ), size ), _vi( vi ) { } ~tVISADMAMemory(); inline ViSession getVisaSession( void ) { return _vi; } private: ViSession _vi; }; tDMAMemory* iBus::allocDMA( u32 size ) { ViStatus status; ViSession vi; tVisaSpecific* specific = reinterpret_cast< tVisaSpecific* >( _osSpecific ); size_t physicalAddress; void* virtualAddress; status = viOpen( specific->sesn, "pxi::memacc", VI_NO_LOCK, 100, &vi ); if( status != VI_SUCCESS ) { return NULL; } status = viMemAlloc( vi, size, (ViPBusAddress) &physicalAddress ); if( status != VI_SUCCESS ) { viClose( vi ); return 0; } status = viMapAddress( vi, VI_PXI_ALLOC_SPACE, physicalAddress, size, VI_NO_LOCK, VI_NULL, &virtualAddress ); if( status != VI_SUCCESS ) { viMemFree( vi, physicalAddress ); viClose( vi ); return 0; } tDMAMemory* dma = new tVISADMAMemory( virtualAddress, physicalAddress, size, vi ); if( NULL == dma ) { viUnmapAddress( vi ); viMemFree( vi, physicalAddress ); viClose( vi ); } return dma; } void iBus::freeDMA( tDMAMemory* mem ) { delete mem; } // // tVISADMAMemory // tVISADMAMemory::~tVISADMAMemory() { viUnmapAddress( _vi ); viMemFree( _vi, getPhysicalAddress() ); viClose( _vi ); }