Array isn't free'd after going out of scope - c++

I have a simple char array used to read from a pipe.
This array is used in an infinite while cycle
int main()
{
mkfifo("process1_write", 0666);
mkfifo("process1_read", 0666);
int fd1,fd2;
fd1 = open(process1_write, O_RDWR);
fd2 = open(process1_read, O_RDONLY| O_NONBLOCK);
std::string outmsg = "{process: drv_rtnode_1, message: hi}";
while (1)
{
char str1[1050];
printf("cycle %d\n\t",i++);
int in = read(fd2, str1, 1024);
if(in>0)
{
printf("message: %s, in: %d\n", str1, in);
write(fd1, outmsg.c_str(), outmsg.size());
}
else
printf("No content received\n");
sleep(1);
}
return 0;
}
As you can see, str1 is instantiated on the stack as a local variable so I'd expect it to be free'd after each while-cycle.
However what I get is the following:
Cycle 1: receiving data from the PIPE, thus enterning if(in>0)
message: {"msg type": "status inst", "ProcessName": "process1", "StatusDetail": "dettaglio componente"}{"msg type": "status ses", "ProcessName": "process1", "GroupName": "MOT", "GroupSts": "Online", "ActiveSession": "PRI", "StatusDetail": "dettaglio sessione"}, in: 251
in = 251, so it's counting the number of characters correctly
Cycle 2: receiving LESS data from the PIPE
This time I'm receiving this message: {"state":"alive"}
But here's the printed output:
message: {"state":"alive"}tus inst", "ProcessName": "process1", "StatusDetail": "dettaglio componente"}{"msg type": "status ses", "ProcessName": "process1", "GroupName": "MOT", "GroupSts": "Online", "ActiveSession": "PRI", "StatusDetail": "dettaglio sessione"} , in: 17
in = 17, so the number of characters is, once again, correctly counted but my array has not been emptied at all
This happens no matter what kind of data I receive.
I also tried changing the code as follows:
char* str1 = new char[1050];
while (1)
{
printf("cycle %d\n\t",i++);
int in = read(fd2, str1, 1024);
if(in>0)
{
printf("message: %s, in: %d\n", str1, in);
write(fd1, outmsg.c_str(), outmsg.size());
}
else
printf("No content received\n");
sleep(1);
delete[] str1;
str1 = new char[1050];
}
But nothing has changed. It behaves exactly the same.

The following:
while (1)
{
char str1[1050];
allocates on the function call stack, but does it like this:
char str1[1050];
while (1)
{
So the location is reused, and only about 1050 bytes callocated.
The problem is, that for strings a nul terminator is needed:
int in = read(fd2, str1, 1024);
if (in > 0)
{
str1[in] = '\0';
Now the overwriting with shorter data does not show prior reads.

Related

Reading stderr from a linux device, after writing to it from c++

When i write to a linux driver / device, in this case i want to put the embedded linux device to sleep:
echo "mem" > /sys/power/state
I get an error on the terminal if the above command fails
[ 2593.061030] dpm_run_callback(): elan_touch_suspend+0x0/0x114 returns 1
[ 2593.067578] PM: Device 0-0015 failed to suspend: error 1
[ 2593.072994] PM: Some devices failed to suspend, or early wake event detected
[ 2593.107845] ==== calc_soc_by_voltageMethod E60U22 ====
And i do this the same in c++:
int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);
If the above command fails, i get the same error on the terminal. now i want to get this error as a string in c++, in shell i can do something like this:
echo "mem" > /sys/power/state 2>/tmp/sleep_error
But i cant figure this out in c++, I need to to try one more time if it fails
What I tryied:
Capturing cerr of the whole program, with freopen doesn't work. When I write to the device from another terminal, and do cat /dev/stderr from another, i get the output in the second one, I tryied to use it:
char byte[1000];
int stderrdevice = open("/dev/stderr", O_RDONLY | O_NOCTTY);
int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);
ssize_t size = read(stderrdevice, &byte, 1000);
printf("Read byte %s\n", byte);
This doesn't work too. Any resources, documentation related to this are welcome
Thanks everyone for help and responding. user17732522 and Nate Eldredge were right. What i was trying to get was the kernel ring buffer, that was printing out to the serial connection. The same thing was in dmesg. I ended up using klogctl to get the errors. I couldn't get only the last line of dmesg with other klogctl options, and the code is a bit chaotic, but here is what I finally used:
bool continueSleeping = true;
int count = 0;
while (continueSleeping == true) {
// https://linux.die.net/man/3/klogctl
klogctl(5, NULL, 0);
log("Trying sleep");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
int fd2 = open("/sys/power/state", O_RDWR);
int status = write(fd2, "mem", 3);
close(fd2);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
log("After sleep");
// get dmesg, and then only lines containing <3>
char *logs_data;
ssize_t len = klogctl(10, NULL, 0);
logs_data = (char *)malloc(len);
klogctl(3, logs_data, len);
vector<string> dmesgErrorsVec;
boost::split(dmesgErrorsVec, logs_data, boost::is_any_of("\n"),
boost::token_compress_on);
// to show whole dmesg
//log("dmesg: " + (string)logs_data);
free(logs_data);
string dmesgErrors;
for (string line : dmesgErrorsVec) {
if (line.find("<3>") != std::string::npos) {
// tesdt
dmesgErrors.append(line);
dmesgErrors.append("\n");
}
}
dmesgErrorsVec.clear();
if (status == -1 or
dmesgErrors.find("PM: Some devices failed to suspend") != std::string::npos) {
log("Failed to suspend, dmesg errors:\n" + dmesgErrors);
log("status: " + to_string(status));
CEG();
count = count + 1;
if (count == 5) {
log("5 failed attemts at suspending, sleep a little longer...");
smartWait(10000);
} else if (count == 15) {
log("15 failed attempts at sleeping...");
// Write to fbink here a sad message
} else {
smartWait(3000);
}
} else {
// Exiting this sleeping hell
log("Tryied going to sleep " + to_string(count) + "times");
continueSleeping = false;
}
}
log("Sleep finished, Exiting going to sleep");

Can not "read" anything through the FUSE file system

I use fuse to build my own file system in MIT 6.824 lab, and the read operation is implemented in this function.
void
fuseserver_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
std::string buf;
int r;
if ((r = yfs->read(ino, size, off, buf)) == yfs_client::OK) {
char* retbuf = (char *)malloc(buf.size());
memcpy(retbuf,buf.data(),buf.size());
//Print the information of the result.
printf("debug read in fuse: the content of %lu is %s, size %lu\n",ino,retbuf, buf.size());
fuse_reply_buf(req,retbuf,buf.size());
} else {
fuse_reply_err(req, ENOENT);
}
//global definition
//struct fuse_lowlevel_ops fuseserver_oper;
//In main()
// fuseserver_oper.read = fuseserver_read;
I print the information of the buf before it return.
The write operation is also implemented, of course.
Then I run a simple test to read out some words.
//test.c
int main(){
//./yfs1 is the mount point of my filesystem
int fd = open("./yfs1/test-file",O_RDWR | O_CREAT,0777);
char* buf = "123";
char* readout;
readout = (char *)malloc(3);
int writesize = write(fd,buf,3);
int readsize = read(fd,readout,3);
printf("%s,%d\n",buf,writesize);
printf("%s,%d\n",readout,readsize);
close(fd);
}
I can get nothing by read(fd,readout,3), but the information printed by the fuseserver_read shows that the buffer is read out successfully before fuse_reply_buf
$ ./test
123,3
,0
debug read in fuse: the content of 2 is 123, size 3
So why the read() in test.c can not read anything from my file system??
Firstly, I've made a mistake to write my test file. The file pointer will point to the end of the file after "write" and of course can read nothing later. So simply reopen the file can make the test work.
Secondly, before read() operation of FUSE, the FUSE will getattr() first and truncate the result of the read() operation with the "size" attribute of the file. So it must be very careful to manipulate the attribute of a file.
There is also a need to notify that you have finished reading by sending an empty buffer, as an "EOF". You can do that by using reply_buf_limited.
Take a look at hello_ll example in the fuse source tree:
static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi) {
(void) fi;
assert(ino == FILE_INO);
reply_buf_limited(req, file_contents, file_size, off, size);
}
static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
off_t off, size_t maxsize)
{
if (off < bufsize)
return fuse_reply_buf(req, buf + off,
min(bufsize - off, maxsize));
else
return fuse_reply_buf(req, NULL, 0);
}

Reuse SuperpoweredDecoder for loading audio files

For benchmarking purposes I repeat loading an .wav-file, processing it offline and saving the output by using the SuperpoweredSDK.
But after some iterations (in my case 4) I get the error "A/libc: invalid address or address of corrupt block 0x5e825000 passed to dlfree" when I try to release the shortIntBuffer.
extern "C" JNIEXPORT void JNICALL
Java_com_example_sebas_superpoweredtest_MainActivity_testDecoderReuse(JNIEnv *env, jobject instance,
jstring apkPath_,
jlong fileOffset,
jlong fileLength,
jstring outputFileName_) {
const char *apkPath = env->GetStringUTFChars(apkPath_, 0);
const char *outputFileName = env->GetStringUTFChars(outputFileName_, 0);
SuperpoweredDecoder decoder;
short int* shortIntBuffer;
FILE* fd;
for(int i = 0; i < 100; ++i) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "RUN %d", i+1);
//open InputFile
const char *openError = decoder.open(apkPath, false, fileOffset, fileLength);
if (openError) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", openError);
return;
};
shortIntBuffer = new short int[decoder.samplesPerFrame * 4 + 16384] {0};
fd = createWAV(outputFileName, decoder.samplerate, 2);
if (!fd) {
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Failed creating File %s", outputFileName);
return;
};
//process samples
unsigned int samplesDecoded;
while (true) {
// Decode one frame. samplesDecoded will be overwritten with the actual decoded number of samples.
samplesDecoded = decoder.samplesPerFrame;
if (decoder.decode(shortIntBuffer, &samplesDecoded) == SUPERPOWEREDDECODER_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error while decoding samples.");
break;
}
if (samplesDecoded < 1) break;
// Write the audio to disk.
fwrite(shortIntBuffer, 1, samplesDecoded * 4, fd);
};
//close resources
if(fd) {
closeWAV(fd);
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Closed wav.");
}
delete[](shortIntBuffer); // <- SIGSEGV (signal SIGSEGV: invalid address (fault address: 0xdeadbaad))
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Deleted shortInBuffer");
}
env->ReleaseStringUTFChars(apkPath_, apkPath);
env->ReleaseStringUTFChars(outputFileName_, outputFileName);
}
I don't understand why the code works fine for the first iterations but not for all iterations. I would be grateful to hear from you to solve this problem.
Thanks in advance
This is the LLDB-Frame when I get the message: "Fatal signal 11 (SIGSEGV) at 0xfde0fdec (code=1), thread 9779 (uperpoweredtest)"

I want to copy the data in (wchar_t *)buffer but i am unable to do so bcz there are other incompatible types,typecasting but not getting the result?

I want to print buffer data at one instance avoiding all other wprintf instances but unable to convert data in compatible type with buffer.
Have a look at code:
Kindly tell me how to get through it:
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
PEVT_VARIANT pRenderedValues = NULL;
WCHAR wsGuid[50];
LPWSTR pwsSid = NULL;
//
// Beginning of functional Logic
//
for (;;)
{
if (!EvtRender(hContext, hEvent, EvtRenderEventValues, dwBufferSize, pRenderedValues, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
dwBytesToWrite = dwBufferSize;
pRenderedValues = (PEVT_VARIANT)malloc(dwBufferSize);
if (pRenderedValues)
{
EvtRender(hContext, hEvent, EvtRenderEventValues, dwBufferSize, pRenderedValues, &dwBufferUsed, &dwPropertyCount);
}
else
{
printf("malloc failed\n");
status = ERROR_OUTOFMEMORY;
break;
}
}
}
Buffer = (wchar_t*) malloc (1*wcslen(pRenderedValues[EvtSystemProviderName].StringVal));
//
// Print the values from the System section of the element.
wcscpy(Buffer,pRenderedValues[EvtSystemProviderName].StringVal);
int i = wcslen(Buffer);
if (NULL != pRenderedValues[EvtSystemProviderGuid].GuidVal)
{
StringFromGUID2(*(pRenderedValues[EvtSystemProviderGuid].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wcscpy(Buffer+i,(wchar_t*)pRenderedValues[EvtSystemProviderGuid].GuidVal);
wprintf(L"Provider Guid: %s\n", wsGuid);
}
//Getting "??????" on screen after inclusion of guidval tell me the correct way to copy it??
wprintf(L"Buffer = %ls",Buffer);
//Also tell the way to copy unsigned values into buffer
wprintf(L"EventID: %lu\n", EventID);
wprintf(L"Version: %u\n", pRenderedValues[EvtSystemVersion].ByteVal);
wprintf(L"Level: %u\n", pRenderedValues[EvtSystemLevel].ByteVal);
wprintf(L"EventRecordID: %I64u\n", pRenderedValues[EvtSystemEventRecordId].UInt64Val);
if (EvtVarTypeNull != pRenderedValues[EvtSystemActivityID].Type)
{
StringFromGUID2(*(pRenderedValues[EvtSystemActivityID].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wprintf(L"Correlation ActivityID: %s\n", wsGuid);
}
if (EvtVarTypeNull != pRenderedValues[EvtSystemRelatedActivityID].Type)
{
StringFromGUID2(*(pRenderedValues[EvtSystemRelatedActivityID].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wprintf(L"Correlation RelatedActivityID: %s\n", wsGuid);
}
wprintf(L"Execution ProcessID: %lu\n", pRenderedValues[EvtSystemProcessID].UInt32Val);
wprintf(L"Execution ThreadID: %lu\n", pRenderedValues[EvtSystemThreadID].UInt32Val);
wprintf(L"Channel: %s\n",pRenderedValues[EvtSystemChannel].StringVal);
wprintf(L"Computer: %s\n", pRenderedValues[EvtSystemComputer].StringVal);
//
// Final Break Point
//
break;
}
}
The first error is when starting to write to the buffer:
Buffer = (wchar_t*) malloc (1*wcslen(pRenderedValues[EvtSystemProviderName].StringVal));
wcscpy(Buffer,pRenderedValues[EvtSystemProviderName].StringVal);
StringVal points to a wide character string with a trailing null byte, so you should
Buffer = malloc (sizeof(wchar_t)*(wcslen(pRenderedValues[EvtSystemProviderName].StringVal)+1));
or even better
Buffer = wcsdup(pRenderedValues[EvtSystemProviderName].StringVal);
Second error is when appending the GUID.
You are not allocating enough memory, you are just appending to the already full Buffer. And you are appending the raw GUID, not the GUID string. You should replace
int i = wcslen(Buffer);
wcscpy(Buffer+i,(wchar_t*)pRenderedValues[EvtSystemProviderGuid].GuidVal);
with something like
// Attention: memory leak if realloc returns NULL! So better use a second variable for the return code and check that before assigning to Buffer.
Buffer = realloc(Buffer, wcslen(Buffer) + wcslen(wsGuid) + 1);
wcscat(Buffer,wsGuid);
Also:
Besides, you should do better error checking for EvtRender. And you should check dwPropertyCount before accessing pRenderedValues[i].
BTW, wprintf(L"Buffer = %s",Buffer); (with %s instead of %ls) is sufficient with wprintf.
And to your last question: if you want to append unsigned values to a buffer you can use wsprintf to write to a string. If you can do it C++-only then you should consider using std::wstring. This is much easier for you with regard to allocating the buffers the right size.

malloc and snprintf bus core dump

Function which worked previously, suddenly refuses cooperation. More precisely this snippet:
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
Program fails one line after "line 82" (no longer line 82, but it's only a debugging stop) with Segmentation Fault (core dumped).
If I change
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1); to
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
I get Bus Error: Code dumped instead. I'm working on this program for quite a long time, and I have a feeling it's something obvious, that I'm constantly overlooking because of exhaustion, but no programmer friends to ask for help at this time.
Whole function for context:
char* myUIDs; //string containing all UID-s, separated by colon
void printProcessInformation(char pid[],int isSetP, int isSetN, int isSetU){
//find full path name to your "stat" file
//DIR *dir;
//struct dirent *ent;
//Creating string with /proc/PID
char * s = malloc(snprintf(NULL, 0, "%s%s", "/proc/", pid) + 1);
sprintf(s, "%s%s", "/proc/", pid);
//Creating string with /proc/PID/psinfo (full path)
char * fullPath = malloc(snprintf(NULL, 0, "%s%s", s, "/psinfo") + 1);
sprintf(fullPath, "%s%s", s, "/psinfo");
free(s);
//printf("%s\n",fullPath);
//Reading data from file
FILE* file = fopen(fullPath, "r");
printf("line 37\n");
char* buffer;
buffer = (char*) malloc(sizeof(psinfo_t));
printf("line 40\n");
if(file == NULL)
{
//perror("Error: Couldn't open file");
return;
}
fread((void *)buffer, sizeof(psinfo_t), 1, file);
psinfo_t* pData = (psinfo_t*) buffer;
time_t sTime=pData->pr_start.tv_sec;
int pr_pid=pData->pr_pid;
char* fname=pData->pr_fname;
free(buffer);
buffer = (char*) malloc(sizeof(stat));
stat(fullPath,buffer);
struct stat* fileStat=(struct stat*) buffer;
fclose(file);
int userId=fileStat->st_uid;
struct passwd* pw=getpwuid(userId);
char* uid=pw->pw_name;
printf("line 58\n");
if(isSetU<0){
//Print results
printf("%8s", uid);
if(isSetP>0)
printf(" %5d",pr_pid);
printf(" %16s %.24s\n", fname, ctime(&sTime));
free(buffer);
}else{
//Or else, add UID to UIDS if it didn't appear before
//check if UID is in UIDS
printf("line 70\n");
char * s2 = malloc(snprintf(NULL, 0, "%s:%d", "", userId) + 1);
printf("line 72\n");
snprintf(s2, "%s:%d", "", userId);
if(strstr(myUIDs,s2)!=NULL){
free(s2);
free(buffer);
return;
}
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
}
}
There are several issues I see on further review...
In a nutshell, the error you are getting does not appear to be the result of the line you're executing, rather, a side effect of a previous corruption of memory.
Where do you initialize myUIDs? It looks like you could be accessing it when it has not been defined based on the code provided
You are assigning fname from pData which is a pointer to the dynamically allocated buffer... which you subsequently free on the next line of execution, which means that fname is now pointing to deallocated memory. Yet you attempt to read from it later in the code... which may well be leading you off on a random walk through memory.
There are multiple instances in the code where you are dynamically allocating memory, and then attempting to use it without ever validating that you actually got the allocation you requested.
You are calling malloc() based on the return value from snprintf() without ever validating that snprintf() returned you a non-negative value. Though, I doubt this is an issue, it's unwise.
To be sure, the symptoms you are describing are the result of the corruption of the heap. The question is where. I would strongly recommend the use of valgrind.
In addition, if it is available, have a look at asprintf() instead of the malloc( snprintf() ) work you are doing.