I have a very serious problem with Embarcadero C++Builder 10.2.2 when compiling a mid-sized in-house application with the "classic" BCC32 compiler.
There's a class to wrap up some DLL functions responsible for reading the number of available hardware USB-interface boxes used for a connection interface and their serial numbers as string. The code below compiles without a flaw when using BCC32, as well as with BCC32c, but during runtime the BCC32 version crashes horribly, while everything works well with BCC32c.
The number of connected devices is sucessfully detected in both cases (which is 2 in my setup) but instead of returning the correct UsbDeviceSerialNo in
FDllPointers.GetUSBDeviceSN()
(for example 126739701012387721219679016621) there's only garbage in there:
��\x18.
In the second iteration of
for (unsigned int UsbDeviceNo = 0; UsbDeviceNo < 32; ++UsbDeviceNo)
there's an 'Access violation at address 00000000...' in the line
memset(UsbDeviceSerialNo, 0, SerNoBufferSize);
std::size_t TComUsbRoot::RefreshInterfaces()
{
// Note: This function does not work correctly when compiled
// with Borland BCC32 due to offset errors and AVs!!
// I don't have a clue, why this is the case at the moment.
const unsigned int SerNoBufferSize = 40;
unsigned long UsbDeviceMask = 0;
char UsbDeviceSerialNo[SerNoBufferSize];
// Clear the current interfaces
FInterfaces.clear(); // <-- std::vector<TComUsbInterface>
// Get the currently available interface count
int InterfaceCount = FDllPointers.GetAvailableUSBDevices(&UsbDeviceMask); // <-- int WINAPI CC_GetAvailableUSBDevices(unsigned long * DeviceMask); (from DLL)
// We need at least one interface to proceed
if (!InterfaceCount)
return 0;
// Check all USB device numbers
for (unsigned int UsbDeviceNo = 0; UsbDeviceNo < 32; ++UsbDeviceNo)
{
// Check the USB device mask
if (((1 << UsbDeviceNo) & UsbDeviceMask) != 0)
{
// Set the serial no to zeroes
memset(UsbDeviceSerialNo, 0, SerNoBufferSize);
// Get the USB device's serial number
int Result = FDllPointers.GetUSBDeviceSN(
UsbDeviceNo,
UsbDeviceSerialNo,
SerNoBufferSize
);
if (Result != 0)
{
throw Except(
std::string("ComUSB: Error while reading the USB device's serial number")
);
}
// Convert the serial number to wstring
std::wstring SerialNo(CnvToWStr(UsbDeviceSerialNo));
// Create a new interface object with the USB device's parameters
TComUsbInterface Interface(
*this,
UsbDeviceNo,
SerialNo,
FDllPointers,
FLanguage
);
// Add it to the vector
FInterfaces.push_back(Interface);
}
}
// Return the size of the interfaces vector
return FInterfaces.size();
}
I simply don't know what's wrong here, as everything is allright with the new, Clang-based compiler. Unfortunately I cannot use the new compiler for this project, as the code completion (which is crappy and compiler-based in C++Builder and feels like using an early BETA edition of somtehing) makes the IDE crash 5 times an hour and the overall compilation time can be simply unbearable, even with the use of precompiled headers.
Related
I am using visual studio 2015 in 32bit mode to compile a dll(VSDll) which calls the functions written in another dll (MATLAB function exported as dll by MATLAB C++ compiler). This VSDLL is then called by an .exe file. Now, I can successflly compile the code into debug and release DLLs. I can also successfully run the release dll from the .exe file. It runs without any problem. But when I try to run the code in debug mode in visual studio I get the following error Error message.
This figure has the register information and the stack frame where the error occurs.Stack Frame and registers. Also attached the stack trace information here. Stack trace.
This might be a silly error but I am new to C++ and I don't have a very deep understanding of memory heaps and stacks. I tried enabling/disabling different settings in the debug mode as suggested in other answers which have worked for others but nothing works in my case. I was using the Visual studio professional version before and I could debug without this error. Now recently I had to change to visual studio community edition and since then I have this problem only when I try to set breakpoints in my code and debug it. Could this be the problem? Another thing I have noticed is, I am using Visual studio to compile various MATLAB functions as dll and use them to build customized dlls to run in TRNExe. Each of it works fine in the release mode, but in debug mode, everytime the same boost_log-vc110-mt-1_49.dll that breaks down and at the same memory register 0x7e37a348.
Can anyone please help me solving this error? I appreciate any ideas or suggestions regarding what the problem could be.
Please see the warning messages here. Could this be the source of the problem?Warning message
I have produced a minimal reproducible example below. It's still free lines of code. Another bottleneck for this is, I am trying to co-simulate between Trnsys and MATLAB. Trnsys has it's components written as Type DLLs (Fortran or C++) and it has a structure for this dll. I am trying to export the MATLAB function as dll, call it in the Trnsys type at required parts of the code and compile it as the DLL to run in Trnsys simulation studio. So, C++ links the MATLAB dll to the TRNDll which is the TRNSYS kernel library. I don't know how to do that as a minimal reproducible example. Anyways, I have compiled the MATLAB code to add two numbers and call it in the Type201.cpp(Respecting the TRNSYS structure) and compiled it into the DLL to run in TRNSYS studio. It works there. But when I try to run the Type201.cpp in debug mode, I still get the exact same error as before at the exact stack frame and the register with boost_log-vc110-mt-1_49.dll.
Type 201.cpp code is below
extern "C" __declspec(dllexport) void TYPE201(void)
{
double a;
double b;
double Timestep, Time, StartTime, StopTime;
int index, CurrentUnit, CurrentType;
mxArray* x_ptr ;
mxArray* y_ptr ;
mxArray* z_ptr = NULL;
double* output = NULL;
//Get the Global Trnsys Simulation Variables
Time = getSimulationTime();
Timestep = getSimulationTimeStep();
CurrentUnit = getCurrentUnit();
CurrentType = getCurrentType();
StartTime = getSimulationStartTime();
StopTime = getSimulationStopTime();
//Set the Version Number for This Type
if (getIsVersionSigningTime())
{
int v = 17;
setTypeVersion(&v);
return;
}
//Do All of the Last Call Manipulations Here
if (getIsLastCallofSimulation())
{
addlibTerminate();
mclTerminateApplication();
return;
}
//Perform Any "End of Timestep" Manipulations That May Be Required
//Do All of the "Very First Call of the Simulation Manipulations" Here
if (getIsFirstCallofSimulation())
{
//Tell the TRNSYS Engine How This Type Works
int npar = 2;
int nin = 2;
int nder = 0;
int nout = 1;
int mode = 1;
int staticStore = 0;
int dynamicStore =1;
setNumberofParameters(&npar);
setNumberofInputs(&nin);
setNumberofDerivatives(&nder);
setNumberofOutputs(&nout);
setIterationMode(&mode);
setNumberStoredVariables(&staticStore, &dynamicStore);
return;
}
//Do All of the "Start Time" Manipulations Here - There Are No Iterations at the Intial Time
if (getIsStartTime())
{
index = 1; a = getInputValue(&index);
index = 2; b = getInputValue(&index);
if (!mclInitializeApplication(NULL, 0))
{
//fprintf(stderr, "Could not initialize the application.\n");
exit(1);
}
if (!addlibInitialize())
{
//fprintf(stderr, "Could not initialize the library.\n");
exit(1);
}
//Read in the Values of the Inputs from the Input File
return;
}
if (getIsEndOfTimestep())
{
return;
}
//---------------------------------------------------------------------------------------------------------------------- -
//ReRead the Parameters if Another Unit of This Type Has Been Called Last
//Get the Current Inputs to the Model
index = 1;
a = getInputValue(&index);
index = 2;
b = getInputValue(&index);
int noutput = getNumberOfOutputs();
//Create an mxArray to input into mlfAdd
x_ptr = mxCreateDoubleMatrix(1, 1, mxREAL);
y_ptr = mxCreateDoubleMatrix(1, 1, mxREAL);
memcpy(mxGetPr(x_ptr), &a, 1 * sizeof(double));
memcpy(mxGetPr(y_ptr), &b, 1 * sizeof(double));
mlfAdd(1, &z_ptr, y_ptr, x_ptr);
output = mxGetPr(z_ptr);
index = 1;
setOutputValue(&index, output);
return;
}
Then this is the MATLAB function to add two numbers.
function [s] = add(a,b)
s = a+b;
end
I complied this into dll via command line using
mcc -B csharedlib:addlib add.m
This is likely because some std classes and boost classes have different layout for release and debug builds. In debug builds additional members are inserted via macros to enable better debugging experience like iterator debugging and such. So as documented by Microsoft it is undefined behavior to mix code linked to different c++ runtime. The matlab dll is build in release mode and linked to c++ release runtime so it shouldn't be used by code linked to debug libraries!
Currently, I am working on real time interface with Visual Studio C++.
I faced problem is, when buffer is running for data store, that time .exe is not responding at the point data store in buffer. I collect data as 130Hz from motion sensor. I have tried to increase virtual memory of computer, but problem was not solved.
Code Structure:
int main(){
int no_data = 0;
float x_abs;
float y_abs;
int sensorID = 0;
while (1){
// Define Buffer
char before_trial_output_data[][8 * 4][128] = { { { 0, }, }, };
// Collect Real Time Data
x_abs = abs(inchtocm * record[sensorID].y);
y_abs = abs(inchtocm * record[sensorID].x);
//Save in buffer
sprintf(before_trial_output_data[no_data][sensorID], "%d %8.3f %8.3f\n",no_data,x_abs,y_abs);
//Increment point
no_data++;
// Break While loop, Press ESc key
if (GetAsyncKeyState(VK_ESCAPE)){
break;
}
}
//Data Save in File
printf("\nSaving results to 'RecordData.txt'..\n");
FILE *fp3 = fopen("RecordData.dat", "w");
for (i = 0; i<no_data-1; i++)
fprintf(fp3, output_data[i][sensorID]);
fclose(fp3);
printf("Complete...\n");
}
The code you posted doesn't show how you allocate more memory for your before_trial_output_data buffer when needed. Do you want me to guess? I guess you are using some flavor of realloc(), which needs to allocate ever-increasing amount of memory, fragmenting your heap terribly.
However, in order for you to save that data to a file later on, it doesn't need to be in continuous memory, so some kind of list will work way better than an array.
Also, there is no provision in your "pseudo" code for a 130Hz reading; it processes records as fast as possible, and my guess is - much faster.
Is your prinf() call also a "pseudo code"? Otherwise you are looking for trouble by having mismatch of the % format specifications and number and type of parameters passed in.
I have no experience in audio programming and C++ is quite low level language so I have a little problems with it. I work with ASIO SDK 2.3 downloaded from http://www.steinberg.net/en/company/developers.html.
I am writing my own host based on example inside SDK.
For now I've managed to go through the whole sample and it looks like it's working. I have external sound card connected to my PC. I've successfully loaded driver for this device, configured it, handled callbacks, casting data from analog to digital etc. common stuff.
And part where I am stuck now:
When I play some track via my device I can see bars moving in the mixer (device's software). So device is connected in right way. In my code I've picked the inputs and outputs with the names of the bars that are moving in mixer. I've also used ASIOCreateBuffers() to create buffer for each input/output.
Now correct me if I am wrong:
When ASIOStart() is called and driver is in running state, when I input the sound signal to my external device I believe the buffers get filled with data, right?
I am reading the documentation but I am a bit lost - how can I access the data being sent by device to application, stored in INPUT buffers? Or signal? I need it for signal analysis or maybe recording in future.
EDIT: If I had made it to complicated then in a nutshell my question is: how can I access input stream data from code? I don't see any objects/callbacks letting me to do so in documentation.
The hostsample in the ASIO SDK is pretty close to what you need. In the bufferSwitchTimeInfo callback there is some code like this:
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
int ch = asioDriverInfo.bufferInfos[i].channelNum;
if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
{
char* buf = asioDriver.bufferInfos[i].buffers[index];
....
Inside of that if block asioDriver.bufferInfos[i].buffers[index] is a pointer to the raw audio data (index is a parameter to the method).
The format of the buffer is dependent upon the driver and that can be discovered by testing asioDriverInfo.channelInfos[i].type. The types of formats will be 32bit int LSB first, 32bit int MSB first, and so on. You can find the list of values in the ASIOSampleType enum in asio.h. At this point you'll want to convert the samples to some common format for downstream signal processing code. If you're doing signal processing you'll probably want convert to double. The file host\asioconvertsample.cpp will give you some idea of what's involved in the conversion. The most common format you're going to encounter is probably INT32 MSB. Here is how you'd convert it to double.
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
int ch = asioDriverInfo.bufferInfos[i].channelNum;
if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
{
switch (asioDriverInfo.channelInfos[i].type)
{
case ASIOInt32LSB:
{
double* pDoubleBuf = new double[_bufferSize];
for (int i = 0 ; i < _bufferSize ; ++i)
{
pDoubleBuf[i] = *(int*)asioDriverInfo.bufferInfos.buffers[index] / (double)0x7fffffff;
}
// now pDoubleBuf contains one channels worth of samples in the range of -1.0 to 1.0.
break;
}
// and so on...
Thank you very much. Your answer helped quite much but as I am inexperienced with C++ a bit :P I find it a bit problematic.
In general I've written my own host based on hostsample. I didn't implement asioDriverInfo structure and use common variables for now.
My first problem was:.
char* buf = asioDriver.bufferInfos[i].buffers[index];
as I got error that I can't cast (void*) to char* but this probably solved the problem:
char* buf = static_cast<char*>(bufferInfos[i].buffers[doubleBufferIndex]);
My second problem is with the data conversion. I've checked the file you've recommended me but I find it a little black magic. For now I am trying to follow your example and:
for (int i = 0; i < inputBuffers + outputBuffers; i++)
{
if (bufferInfos[i].isInput)
{
switch (channelInfos[i].type)
{
case ASIOSTInt32LSB:
{
double* pDoubleBuf = new double[buffSize];
for (int j = 0 ; j < buffSize ; ++j)
{
pDoubleBuf[j] = bufferInfos[i].buffers[doubleBufferIndex] / (double)0x7fffffff;
}
break;
}
}
}
I get error there:
pDoubleBuf[j] = bufferInfos[i].buffers[doubleBufferIndex] / (double)0x7fffffff;
which is:
error C2296: '/' : illegal, left operand has type 'void *'
What I don't get is that in your example there is no table there: asioDriverInfo.bufferInfos.buffers[index] after bufferInfos and even if I fix it... to what kind of type should I cast it to make it work. P
PS. I am sure ASIOSTInt32LSB data type is fine for my PC.
The ASIO input and output buffers are accessible using void pointers, but using memcpy or memmove to access I/O buffer will create a memory copy which is to be avoided if you are doing real-time processing. I would suggest casting the pointer type to int* so you can directly access them.
It's also very slow in real-time processing to cast types 1 by 1 when you have like 100+ audio channels when AVX2 is supported on most CPUs.
_mm256_loadu_si256() and _mm256_cvtepi32_ps() will do the conversion much faster.
I'm writing a small utility to parse xfs filesystem on windows.
For small size image <5GB my utility is working fine: I'm able to list all files and directories.
But when I try to parse large xfs image > 30GB. It is giving wrong results.
I'm using _fseeki64 and _ftelli64 for seeking and fread for reading particular block.
One of thing I've notice is that _fseeki64 is not wroking properly.
Below is my seek function which seek to particular group number and block number.
int FileSystemReadXFS::SeekToGroupBlock(uint16_t grpNum, uint64_t blockNum)
{
int error = -1;
//Seek to beginning
if(_fseeki64(m_fileSystemInfo.fp, (__int64)0, SEEK_SET) != 0)
{
PRINT_SEEK_ERROR;
goto BAILOUT;
}
__int64 currPtr = 0;
//Seek to destination group
if(grpNum > 0)
{
if(_fseeki64(m_fileSystemInfo.fp, (__int64)(grpNum*m_fileSystemInfo.SizeOfBlockGroup*m_fileSystemInfo.BlockSize), SEEK_SET))
{
PRINT_SEEK_ERROR;
goto BAILOUT;
}
currPtr = _ftelli64(m_fileSystemInfo.fp);
}
//Seek to destination block in group
if(blockNum > 0)
{
if(_fseeki64(m_fileSystemInfo.fp, (__int64)(blockNum*m_fileSystemInfo.BlockSize), SEEK_CUR))
{
PRINT_SEEK_ERROR;
goto BAILOUT;
}
currPtr = _ftelli64(m_fileSystemInfo.fp);
}
error = 0;
BAILOUT:
return error;
}
However the above function is taking me to wrong postion.
For example when I want to seek to group number = 2 with m_fileSystemInfo.SizeOfBlockGroup = 2043982
and m_fileSystemInfo.BlockSize = 4096.
I'm expecting currPrt = 2043982*4096*2 = 16744300544 (0x3E609C000), But _ftelli64 is returning (0xE609C000).
Please suggest what could be going wrong. Also please advice what is the best way to deal with large files on windows in c++.
Update::
I found that the seekOffset is getting limited to 8154365952 (0x1e609c000) instead of actual
value of 16744300544 (0x3e609c000) inspite of me using __int64.
So.
_int64 seekOff = (_int64)(grpNum*m_fileSystemInfo.SizeOfBlockGroup*m_fileSystemInfo.BlockSize)
= 2*2043982*4096
is giving 8154365952 instead of 16744300544.
I'm not sure what could the reason as everything is in __int64.
Apparently the problem was with calculation of seek offset. It was generating integer overflow.
Hence I have to convert everything to __int64 even-though I'm working on 64 bits application. I was thinking compiler might be able to do this for me.
__int64 grpNum = 2;
__int64 sizeOfBlockGroup = 2043982;
__int64 blockSize = 4096;
__int64 seekOffSet = grpNum*sizeOfBlockGroup*blockSize;
which works fine with _fseeki64 and __ftelli64.
Your best bet is to use Win32 API directly and not go through the C RunTime.
Use CreateFile to open the file and SetFilePointerEx to seek
The functions you're calling will end up calling these APIs anyway. In Visual studio you have the CRT code so you can step into _fseeki64 and possibly see where it goes wrong.
I have the following problem.
I use the following function to receive a string from a buffer until a newline occurs.
string get_all_buf(int sock) {
int n = 1, total = 0, found = 0;
char c;
char temp[1024*1024];
string antw = "";
while (!found) {
n = recv(sock, &temp[total], sizeof(temp) - total - 1, 0);
if (n == -1) {
break;
}
total += n;
temp[total] = '\0';
found = (strchr(temp, '\n') != 0);
if (found == 0){
found = (strchr(temp, '\r\n') != 0);
}
}
antw = temp;
size_t foundIndex = antw.find("\r\n");
if (foundIndex != antw.npos)
antw.erase ( antw.find ("\r\n"), 2 );
foundIndex = antw.find("\n");
if (foundIndex != antw.npos)
antw.erase ( antw.find ("\n"), 2 );
return answ;
}
So use it like this:
string an = get_all_buf(sClient);
If I create an exe file everything works perfectly.
But if I create a dll and run it using rundll32 the application closes at "string an = get_all_buf(sClient);" without any error message...
I tried to fix this for hours now, and I am currently a bit desperate...
P.S. sorry for obvious errors or bad coding style, I just started learning C++.
char temp[1024*1024];
declares a 1Mb structure on the stack. This may be too large and overflow available stack memory. You could instead give it static scope
static char temp[1024*1024];
or allocate it dynamically
char* temp = (char*)malloc(1024*1024);
// function body
free(temp);
Alternatively, assuming the mention of run32.dll means you're working on Windows, you could investigate keeping it on the stack by using the /STACK linker option. This probably isn't the best approach - you've already found it causes problems when you change build settings or try to target other platforms.
Instead of creating temp variable on the stack, I'd create it dynamically (on the heap), but not using raw malloc and free as showed in a previous answer, but using modern C++ and std::vector:
#include <vector>
std::vector<char> temp(1024*1024);
This is exception safe, and you don't have to pay attention to release the allocated memory: std::vector's destructor will do that automatically (also in case of exceptions thrown).
Instead of sizeof(temp), in your code you can use temp.size() (which will return the count of elements in the vector, and since this is a vector of chars, it will return just the total vector size in chars i.e. in bytes).
You can still use operator[] for std::vector, as you do for raw C arrays.
Note also that if you are building a DLL and the above function is exposed at the DLL interface, since this function has a C++ interface with a STL class (std::string) at the boundary, you must pay attention that both your DLL and your clients are built with dynamic linking to the same CRT, and with the same compiler and the same compiler settings (e.g. you can't mix a DLL built with VS2008/VC9 with a .EXE built with VS2010/VC10, or a release-build DLL with a debug-build EXE built with the same compiler).