I'm currently working on a mac application to the transfer file from mac to mtp device such as usb.
I use the code below to add it:
LIBMTP_file_t *genfile;
char *AbsolutePath = NULL;
char *FileNameOnly = NULL;
QFileInfo fileInfo(filename);
FileNameOnly = convertQStr2char(fileInfo.fileName());
AbsolutePath = convertQStr2char(fileInfo.absoluteFilePath());
genfile = LIBMTP_new_file_t();
genfile->filesize = filesize;
genfile->filename = FileNameOnly;
genfile->filetype = file_type;
genfile->parent_id = CurrentFolderID;
genfile->storage_id = PulsDeviceMngr->devicestorage->id;
if ((genfile->filetype != LIBMTP_FILETYPE_ALBUM) && (genfile->filetype != LIBMTP_FILETYPE_PLAYLIST)) {
ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, AbsolutePath, genfile, ProgressBar, NULL);
if (ret != 0) {
qDebug() << "Error sending file";
LIBMTP_Dump_Errorstack(PulsDeviceMngr->device);
LIBMTP_Clear_Errorstack(PulsDeviceMngr->device);
} else {
PulsDeviceMngr->devicestorage->FreeSpaceInBytes -= filesize;
PulsDeviceMngr->devicestorage->FreeSpaceInObjects--;
}
}
LIBMTP_destroy_file_t(genfile);
This basically what is required by mtp to make it works.
I'm usine QT/C++ to develop the Software.
it seems that the QString is not impacted but only the char . char is needed because the api used only support char . I'm converting QString to char using the following code.
char *mtp_wrapper::convertQStr2char(QString str) {
QByteArray latin_str = str.toLatin1();
char *return_str = latin_str.data();
return return_str;
}
I got an issue to release genfile ?? it seems that the runtime consider that I can't free an not allocated pointer but I use to do it using the line below:
genfile = LIBMTP_new_file_t();
LIBMTP_destroy_file_t(genfile);
There is no precondition to do it. when genfile happens, destroy happened. Some data are allocated on the genfile.
I'm able now to open the file for PTP stat complain that I can not send object
Any idea ?
The problem lies in the convertQStr2char() method. The latin_str object is created on the stack and will be destroyed at the end of the enclosing code block. This object is responsible for management of its internal data.
When you call char *return_str = latin_str.data();, you only copy the pointer to latin_str's internal data. As your method returns, latin_str is destroyed and the memory pointed to by data() is freed, so your returned pointer now points to a freed memory as well.
LIBMTP_destroy_file_t is documented to deallocate memory used by the structure, including any strings. In particular, when you call it, it also tries to free the memory pointed to by FileNameOnly, but - as I explained above - the memory has been already freed by QByteArray's destructor, hence the error.
Since using freed pointer results in an undefined behavior, this may be also the cause of your second issue.
Related
I need debugger I am writing to give me the name of shared lib that program being debugged is linking with, or loading dynamically. I get the rendezvous structure as described in link.h, and answers to other questions, using DT_DEBUG, in the loop over _DYNAMIC[].
First, debugger never hits the break point set at r_brk.
Then I put a break in the program being debugged, and use link_map to print all loaded libraries. It only prints libraries loaded by the debugger, not the program being debugged.
It seems that, the rendezvous structure I am getting belongs to the debugger itself. If so, could you please tell me how to get the rendezvous structure of the program I am debugging? If what I am doing must work, your confirmation will be helpful, perhaps with some hint as to what else might be needed.
Thank you.
// You need to include <link.h>. All structures are explained
// in elf(5) manual pages.
// Caller has opened "prog_name", the debugee, and fd is the
// file descriptor. You can send the name instead, and do open()
// here.
// Debugger is tracing the debugee, so we are using ptrace().
void getRandezvousStructure(int fd, pid_t pd, r_debug& rendezvous) {
Elf64_Ehdr elfHeader;
char* elfHdrPtr = (char*) &elfHeader;
read(fd, elfHdrPtr, sizeof(elfHeader));
Elf64_Addr debugeeEntry = elfHeader.e_entry; // entry point of debugee
// Here, set a break at debugeeEntry, and after "PTRACE_CONT",
// and waitpid(), remove the break, and set rip back to debugeeEntry.
// After that, here it goes.
lseek(fd, elfHeader.e_shoff, SEEK_SET); // offset of section header
Elf64_Shdr secHeader;
elfHdrPtr = (char*) &secHeader;
Elf64_Dyn* dynPtr;
// Keep reading until we get: secHeader.sh_addr.
// That is the address of _DYNAMIC.
for (int i = 0; i < elfHeader.e_shnum; i++) {
read(fd, elfHdrPtr, elfHeader.e_shentsize);
if (secHeader.sh_type == SHT_DYNAMIC) {
dynPtr = (Elf64_Dyn*) secHeader.sh_addr; // address of _DYNAMIC
break;
}
}
// Here, we get "dynPtr->d_un.d_ptr" which points to rendezvous
// structure, r_debug
uint64_t data;
for (;; dynPtr++) {
data = ptrace(PTRACE_PEEKDATA, pd, dynPtr, 0);
if (data == DT_NULL) break;
if (data == DT_DEBUG) {
data = ptrace(PTRACE_PEEKDATA, pd, (uint64_t) dynPtr + 8 , 0);
break;
}
}
// Using ptrace() we read sufficient chunk of memory of debugee
// to copy to rendezvous.
int ren_size = sizeof(rendezvous);
char* buffer = new char[2 * ren_size];
char* p = buffer;
int total = 0;
uint64_t value;
for (;;) {
value = ptrace(PTRACE_PEEKDATA, pd, data, 0);
memcpy(p, &value, sizeof(value));
total += sizeof(value);
if (total > ren_size + sizeof(value)) break;
data += sizeof(data);
p += sizeof(data);
}
// Finally, copy the memory to rendezvous, which was
// passed by reference.
memcpy(&rendezvous, buffer, ren_size);
delete [] buffer;
}
I'm trying to share memory between two processes C# (EXE) and C++ (DLL).
The C++ DLL is dynamically loaded by a Citrix receiver process.
Below is my C# and C++ code:
private void Test()
{
string data = "Hello";
_memoryMap = MemoryMappedFile.CreateOrOpen("14614C87-8D7F-45FC-8D59-DCBF1715A715", data.Length, MemoryMappedFileAccess.ReadWrite);
var stream = _memoryMap.CreateViewStream();
using (BinaryWriter binReader = new BinaryWriter(stream))
{
binReader.Write(data);
}
}
void readFromMemoryMap()
{
HANDLE hMapObject = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"14614C87-8D7F-45FC-8D59-DCBF1715A715");
char buffer[2000];
if (hMapObject == NULL)
{
sprintf(buffer, "OpenFileMapping: GetLastError=%d", GetLastError());
}
char *fileBuffer = (char *)MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, 6);
UnmapViewOfFile(fileBuffer);
CloseHandle(hMapObject);
}
I took care of writing and reading an object sequence. My C# application's memory map handle didn't crash. I have run this code using an administrator account which has rights.
I am facing the below error. Can anyone help me with the case of this error?
I followed below link for fix this issue.
OpenFileMapping ERROR_FILE_NOT_FOUND
Try prefixing the object name with Global\ like it says here: https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory
My goal is to create a simple addon that opens a memory mapped file and gives node raw access to the buffer. The memory mapped file already exists so I don't need to create a new file -- error will be thrown if file not already created (by another process).
Here is what I have so far:
#include <nan.h>
#include <windows.h>
using namespace v8;
void get_shm(const Nan::FunctionCallbackInfo <v8::Value> &info) {
if (info.Length() != 1) {
return Nan::ThrowTypeError("Wrong number of arguments. You must specify size of mapped file!");
}
if (!info[0]->IsNumber()) {
return Nan::ThrowTypeError("Bad argument. Size of mapped file must be a number!");
}
int len = info[0]->Uint32Value();
HANDLE h = OpenFileMappingA(FILE_MAP_WRITE | FILE_MAP_READ, 1, "Global\\_GB_SharedMemory_Read");
if (h == NULL) {
Nan::ThrowTypeError("Couldn't open memory mapped file");
}
char *buf = (char *) MapViewOfFile(h, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, len);
Nan::MaybeLocal<Object> jsbuf = Nan::NewBuffer(buf, len);
info.GetReturnValue().Set(jsbuf.ToLocalChecked());
}
void Init(v8::Local <v8::Object> exports) {
exports->Set(Nan::New("get_shm").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(get_shm)->GetFunction());
}
NODE_MODULE(addon_shm, Init)
Unfortunately node is crashing (presumably due to access violation) at some point after the NewBuffer is returned. It doesn't crash immediately but some unpredictable time after.
I'm not attempting to read/write from the buffer in Javascript. The only line using the add on is this:
const buf=shm.get_shm(10);
Mapped file created by the other process is bigger than 10.
If I use malloc to create the buffer, problem doesn't occur.
If I just call get_shm(10) without storing the result, problem doesn't occur.
Struggling to understand the issue...
I'm trying to use the STK from Stanford to do some realtime wavetable synthesis. I'm using the FMVoices instrument class https://ccrma.stanford.edu/software/stk/classstk_1_1FMVoices.html
and trying to use it in a callback routine defined below.
int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *dataPointer )
{
FMVoices *FM = (FMVoices *) dataPointer;
register StkFloat *samples = (StkFloat *) outputBuffer;
for ( unsigned int i=0; i<nBufferFrames; i++ )
*samples++ = FM->tick();
return 0;
}
The issue, I think, is with the type of that last parameter. I'm getting a runtime error : "0xC0000005: Access violation executing location 0x000000001." Now, this is the way that the callback is supposed to be written for other STK instruments like Clarinet or even the FileLoop class, but there's something funky about FMVoices. The object is passed to openStream (which handles platform specific realtime output) as a pointer to void. The callback is called automatically when the system's audio buffer is full. A code snippet that implements this and DOES work for other instruments is shown below:
int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;
Instrmnt * instrument_FM;
int nFrames = 10000;
try {
instrument_FM = new FMVoices;
}
catch ( StkError & ) {
goto cleanup;
}
instrument_FM->setFrequency(440.0);
// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
try {
dac.openStream( ¶meters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&instrument_FM);
}
catch ( RtError &error ) {
error.printMessage();
Sleep(1000);
goto cleanup;
}
The size of nFrames does not seem to have an effect. It just seemed to me that these types of errors usually come from referencing a pointer to void.
The problem is you are taking the address of a pointer, and passing it into openStream.
// pointer to instrument
Instrmnt * instrument_FM;
// snip ...
// &instrument_FM is a pointer to a pointer! i.e. Instrmnt **
dac.openStream( ¶meters, /* other params */, (void *)&instrument_FM)
The quickest solution is to just get rid of the & in that line.
Now some comments on C++, and some more fixes to your code. The code looks like a mixture of C and Java, and opens up a lot of pitfalls to fall into, one of which led to your problem.
There is no need for dynamically allocating FMVoices . Use the stack just like you did for RtAudio dac.
No need to worry about pointers, and deleteing the memory you allocated
Therefore no memory leaks.
Just write FMVoices instrument_FM;
There is no need to do try/catch in most cases for cleanup since C++ has destructors that trigger at the end of scope, and propagate the error.
If you only use the stack, there is no need to worry about delete and having cleanup operations
Don't ever use goto in C++, it's really not needed. (unlike in C, where it could be used for cleanup).
There are destructors and RAII for that.
Use C++ casts which are more fine-grained, such as static_cast<> and reinterpret_cast<>, instead of C-style casts
See this article for an explanation.
Here's the revised code:
int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;
FMVoices instrument_FM;
instrument_FM.setFrequency(440.0);
// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
// didn't get rid of this try since you want to print the error message.
try {
// note here i need the ampersand &, because instrument_FM is on the stack
dac.openStream( ¶meters, NULL, format, static_cast<unsigned int>(Stk::sampleRate()), &bufferFrames, &tick, reinterpret_cast<void*>(&instrument_FM));
}
catch ( RtError& error ) {
error.printMessage();
}
}
I use function CreateFileMapping MapViewOfFile UnmapViewOfFile to create a shared block on the disk. Can I placement new a class object on this block?
I use VS2003 IDE.
try
{
Sphere *pData = m_pBVH->GetFirstHalfData();
Sphere *p = new(pData)Sphere(center, radius, index);
}
catch (std::exception& e)
{
// Can't catch
}
Placement new error:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
At the Debug Mode, placement new operator may cause a syntax error. It's likely because of the code above, anotate it and try again!
At Release mode, it's OK, but throws exception which is not std::bad_alloc, can't figure out which it is. Maybe there is something with the way shared memory is built. My shared memory creation code is as bellow:
CBVHVertexBuffer::CBVHVertexBuffer(const CString &file, unsigned int size)
{
this->file = file;
this->size = size;
fileHandle = INVALID_HANDLE_VALUE;
mapHandle = INVALID_HANDLE_VALUE;
mapLength = 0;
start = NULL;
end = NULL;
head = NULL;
tail = NULL;
fileHandle = ::CreateFile(
file,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
//::SetFilePointer(fileHandle, size * pickingVertexSize, NULL, FILE_BEGIN);
//::SetEndOfFile(fileHandle);
//mapLength = ::GetFileSize(fileHandle, NULL);
//mapLength = size * pickingVertexSize;
mapHandle = ::CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, 0, size * pickingVertexSize, NULL);
mapLength = ::GetFileSize(fileHandle, NULL);
start = (Sphere*)::MapViewOfFile(mapHandle, FILE_MAP_WRITE, 0, 0, 0);
}
end = start + size;
Clear();
}
I would advice to only use Plain Old Data (POD) in your mapped file, because pointers can become invalid when mapping and unmapping files
In principle, you can use placement new operator (void* operator new (std::size_t size, void* ptr) throw();) to create an object in an already allocated memory buffer.
However, creating objects in file mapping regions should be applied for POD objects. Any raw pointer member (and virtual memory table if any) will not be recommended to be stored in mapped file, because they will be invalidated as soon as the mapping is done in a different address space. You should also take care to manage the memory allocation in this case.
I recommend to take a look at boost interprocess library (they have pretty good support for memory mapped files, including management of the memory buffers - allocation algorithms, object tracking and a pointer-like class for linking objects address-space independent (offset_ptr)).