Using
#include <execinfo.h>
one can access methods for unwinding the stack, at least on a most linux configurations. However, this allows one to fetch a char * to some NTBS (null terminated byte string) which shows some information, but not all of it, especially not:
file names
line numbers
function names
I have written a bash-script which can deduce a line number and a file using objdump and the text address of the instruction, however its use is tedious as I have to copy paste the address of multiple stack frames to it manually.
Given that g++ allows one to include debugging symbols with the -g command line option, how can I parse and access them in c++ programmatically? Debuggers like gdb and valgrind are also capable of accessing this information at runtime somehow: I'm assuming they use some library for that or if they implement it themselves export the functionality as an API. For example, valgrind defines some interesting function declarations in include/pub_tool_debuginfo.h. Unfortunately, I couldn't find anything else. I created this as a starting point:
#include <execinfo.h>
namespace stck {
class stacktrace_t {};
stacktrace_t stacktrace;
std::ostream &operator<<(std::ostream &out, stacktrace_t) {
out << "stacktrace:\n";
size_t max = 256;
void **stackframes = new void *[max];
size_t numel;
while ((numel = backtrace(stackframes, max)) >= max) {
max *= 2;
delete[] stackframes;
stackframes = new void *[max];
}
char **symbols = backtrace_symbols(stackframes, numel);
for(size_t i = 0; i < numel; ++i)
out << symbols[i] << '\n';
delete[] stackframes;
return out;
}
}
source: http://ideone.com/RWoADT
Are there any suggestions to append this code to also output human readable debugging information?
As a note, I'm implementing this for usage with mex, a matlab compiler which uses g[++|cc]. Whenever I'm using the functionality, the program is in a 'good' state, that is an error is detected but noting really has has happened; like a segmentation fault.
For example, one could check if the argument of sqrt is non-negative, and if not use the stck::stacktrace to show where this happened.
update
I think the information is not directly available at runtime (although I'm not sure), but is only available in the executable file, not in the executable text in memory. (Please correct me if I'm wrong.
Hence I think there is no way around parsing the executable file, for example via addre2line:
namespace stck {
std::string getstackframe(char *frame) {
std::string fr(frame);
size_t loc0 = fr.find("(");
size_t loc1 = fr.find(")");
std::stringstream ss;
ss << "addr2line -e " << fr.substr(0, loc0) << " -pfC " << fr.substr(loc0 + 2, loc1 - loc0 - 2);
FILE* pipe = popen(ss.str().c_str(), "r");
char buffer[128];
std::stringstream result;
while(!feof(pipe))
if (fgets(buffer, 128, pipe) != NULL)
result << buffer;
pclose(pipe);
return result.str();
}
class stacktrace_t {};
stacktrace_t stacktrace;
std::ostream &operator<<(std::ostream &out, stacktrace_t) {
out << "stacktrace:\n";
size_t max = 256;
void **stackframes = new void *[max];
size_t numel;
while ((numel = backtrace(stackframes, max)) >= max) {
max *= 2;
delete[] stackframes;
stackframes = new void *[max];
}
char **symbols = backtrace_symbols(stackframes, numel);
for(size_t i = 0; i < numel; ++i)
out << getstackframe(symbols[i]);
out << '\n';
delete[] stackframes;
return out;
}
}
Related
I have a problem with the std::sort-method. In the following code I'm using the std::sort-method to sort a vector of structs (= Highscore). However, when I run this line a "read access violation" exception is thrown in the xmemory-file.
Here are the details:
Exception thrown: read access violation.
_Pnext was 0x217AE3EE9D8. occurred
This is the method where the error occures.
void HighscoreManager::sortAndChangeRanks(bool deleteLast) {
std::sort(_highscores.begin(), _highscores.end());
if (deleteLast && _highscores.size() > MaxHighscores) {
_highscores.pop_back();
}
for (int i = 0; i < _highscores.size(); i++) {
_highscores.at(i).rank = i + 1;
}
}
_highscores is defined as std::vector<Highscore> _highscores; and is filled with values from a file before the method call. This works just fine. When im debugging right before using the sort-Method, the vector is filled with the right values from the file.
This is the implementation of the Highscore-struct:
struct Highscore {
int rank;
std::string name;
int points;
Highscore() {}
Highscore(int r, std::string n, int p) : rank(r), name(std::move(n)), points(p) {}
bool operator<(const Highscore& h1) const {
return points < h1.points;
}
};
Please help me or point me to a direction where the error could lie, I'm out of ideas.
EDIT
Since it was asked in the comments where the vector is used before the call to std::sort, this is the method which is called from the object constructor and the only time the vector is used before the sorting. This way of reading (writing works similarly) from a binary file is based on this.
bool HighscoreManager::loadFromFile() {
std::ifstream in(FileName, std::ios::in | std::ios::binary);
if(!in) {
return false;
}
try {
std::vector<Highscore>::size_type size = 0;
in.read((char*)&size, sizeof(size));
_highscores.resize(size);
in.read((char*)&_highscores[0], _highscores.size() * sizeof(Highscore));
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
in.close();
sortAndChangeRanks(false);
return in.good();
}
I don’t know what’s “optimized” about your high score storage. It seems like just a waste of effort for nothing. You’re not storing millions of high scores. You could just store them as text. The “optimization” can’t be measured in normal use. And if you think you’re optimizing: show measurements. Otherwise you’re fooling yourself and wasting time.
On top of it, you’ve complicated the code enough to that you ran into a problem that took a long time to debug. That’s a learning experience, but strictly speaking you wasted even more time because of it. Your time costs more than runtime, in most cases.
All you needed was trivial text stream I/O that can be done in two minutes. Messing about with binary storage is not advised if you don’t thoroughly understand what’s going on. As it stands, your code will crash or worse if you try reading the high scores written on a machine with different endianness. And now you got to manage endianness of all the numeric data… good luck.
In any case, it’s actually a pessimization, since you constantly reallocate the temporary string buffer. That buffer is not needed. You should resize the string itself an put the data in it.
std::string name(nLen);
in.read(&name[0], name.size());
Here is the current solution I'm using. This works for me and solves my problem, which is with reading/writing an std::string to a binary file and not with the sorting method (Thanks to the comments on the question!). To fix this problem I used parts of this.
reading from a file:
std::ifstream in(FileName, std::ios::in | std::ios::binary);
if(!in) {
return false;
}
try {
std::vector<Highscore>::size_type size = 0;
in.read((char*)&size, sizeof(size));
for(int i = 0; i < size; i++) {
int r, p;
size_t nLen;
in.read((char*)&r, sizeof(int));
in.read((char*)&p, sizeof(int));
in.read((char*)&nLen, sizeof(size_t));
char* temp = new char[nLen + 1];
in.read(temp, nLen);
temp[nLen] = '\0';
std::string name = temp;
delete[] temp;
_highscores.emplace_back(r, name, p);
}
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
in.close();
sortAndChangeRanks(false);
return in.good();
}
writing to a file:
bool HighscoreManager::saveToFile() {
std::ofstream out(FileName, std::ios::out | std::ios::binary);
if(!out) {
return false;
}
std::vector<Highscore>::size_type size = _highscores.size();
try {
out.write((char*)&size, sizeof(size));
for(int i = 0; i < size; i++) {
out.write((char*)&_highscores.at(i).rank, sizeof(int));
out.write((char*)&_highscores.at(i).points, sizeof(int));
size_t nameLen = _highscores.at(i).name.size();
out.write((char*)&nameLen, sizeof(size_t));
out.write((char*)_highscores.at(i).name.c_str(), nameLen);
}
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
out.close();
return out.good();
}
Thank you all for your help!
I want to implement RSA with padding but first I have to find out the length in bytes of the message which is a mpz_class item. Which function would be useful in cpp to accomplish this?
const mpz_class m(argv[1])
What is the length of m in bytes?
Thank you!
#Shawn's comment is correct: The bytes occupied in memory by your class are not what you should be concerned about. Not only does the location of the bytes in memory depend on how your compiler decides to pack them, but their order can also depend on the hardware used.
So, instead of doing some awkward and very fragile memcopy'ish thing that are almost guaranteed to break at some point, you should construct the message yourself (google keyword: Serialization). This also has the advantage that your class can contain stuff that you don't want to add to the message (caches with temp results, or other implementation/optimization stuff).
To the best of my knowledge C++ (unlike f.ex. C#) does not come with build in serialization support, but there are likely to exist libraries that can do a lot of it for you. Otherwise you just have to write your "data member to byte array" functions yourself.
Super simple example:
#include <vector>
#include<iostream>
class myClass
{
int32_t a;
public:
myClass(int32_t val) : a(val) {}
// Deserializer
bool initFromBytes(std::vector<uint8_t> msg)
{
if (msg.size() < 4)
return false;
a = 0;
for (int i = 0; i < 4; ++i)
{
a += msg[i] << (i * 8);
}
return true;
}
// Serializer
std::vector<uint8_t> toBytes()
{
std::vector<uint8_t> res;
for (int i = 0; i < 4; ++i)
{
res.push_back(a >> (i*8));
}
return res;
}
void print() { std::cout << "myClass: " << a << std::endl; }
};
int main()
{
myClass myC(123456789);
myC.print();
std::vector<uint8_t> message = myC.toBytes();
myClass recreate(0);
if (recreate.initFromBytes(message))
recreate.print();
else
std::cout << "Error" << std::endl;
return 0;
}
I'm building a library consisting of a class (MyTotp) that has an object as property (Profile).
In the main test function I built a vector of Profile objects and a for loop which iterates through vector assigning the object to the MyTotp property and calculating the result.
The program compiles correctly. When it is run the first loop is executed correctly but the second one raise a segmentation fault (core dump).
Debugging the program I noticed that the error appears after the second re-allocation of memory (required_size may change (and it does into the test) in each loop) for array uint8_t * secret as pointed into the code. I thought the re-allocation was the cause for the memory failure, but I can't exclude anything
Below the significant code...
MyTotp.h
class buzztotp {
public:
[...]
Profile profile;
[...]
};
}
MyTotp.cpp
void MyTotp::getPaddedSecret(uint8_t * out) {
uint8_t* secret = this->profile.getSecret();
uint32_t secret_len = this->profile.getSecretLen();
for (int i = 0; i < this->required_size; i++) {
int index = i % secret_len;
out[i] = secret[index];
}
delete[] secret; secret = NULL;
}
uint32_t MyTotp::generateTOTP() {
this->preprocess(); //It calculates, according to profile properties, this->required_size
uint8_t* secret = new uint8_t[this->required_size]; //Here the memory error while debugging
this->getPaddedSecret(secret);
[...]
delete[] secret; secret = NULL;
return (...);
}
Profile.h
uint8_t* Profile::getSecret() const {
uint8_t* out;
out = new uint8_t[this->secret_len]; //#Edit1 - Error now here
//memcpy(out, this->secret, this->secret_len*sizeof(uint8_t));
std::copy(this->secret_vector.begin(), this->secret_vector.end(), out);
return out;
}
main.cpp
int main(void) {
currentDir();
XmlResourceManager xmlresman;
xmlresman.setFilename(std::string("...myfile.xml"));
/*
* Here the vector<Profile> xmlresman::profiles is built as:
*
* Profile __profile;
* [...]
* this->profiles.push_back(__profile);
*/
xmlresman.parseXml();
for (unsigned int i = 0; i < xmlresman.profiles.size(); i++) {
MyTotp mytotp;
buzztotp.profile = xmlresman.profiles[i];
try {
std::cout << "TOTP: " << mytotp.generateTOTP() << std::endl;
} catch (std::string str) {
std::cerr << str << std::endl;
}
//mytotp.~mytotp();
}
return 0;
}
Any suggestions?
Edit1
I used two strategies (I can't figure the best out) for elaborating a uint8_t* by a function: generating/instantiating it into the parent block and passing it to the function as an argument OR returning a generated/instantiated pointer into the function itself. Running the debug again it seems the error is at the re-allocation of out into Profile::getSecret(). I'm starting to get confused about the behaviour of the program run.
The explicit destructor (mytotp) into the main loop was only a past try: it is a misprint, completely useless by now.
Edit2
Cancelling the explicit constructor seems to solve the problem.
I am building an FTP client in C++ for personal use and for the learning experience, but I have run into a problem when allocating memory for storing LIST responses. The library I am using for FTP requests is libcurl which will call the following function when it receives a response from the server:
size_t FTP_getList( char *ptr, size_t size, size_t nmemb, void *userdata) {
//GLOBAL_FRAGMENT is global
//libcurl will split the resulting list into smaller approx 2000 character
//strings to pass into this function so I compensate by storing the leftover
//fragment in a global variable.
size_t fraglen = 0;
if(GLOBAL_FRAGMENT!=NULL) {
fraglen = strlen(GLOBAL_FRAGMENT);
}
size_t listlen = size*nmemb+fraglen+1;
std::cout<<"Size="<<size<<" nmemb="<<nmemb;
char *list = new char[listlen];
if(GLOBAL_FRAGMENT!=NULL) {
snprintf(list,listlen,"%s%s",GLOBAL_FRAGMENT,ptr);
} else {
strncpy(list,ptr,listlen);
}
list[listlen]=0;
size_t packetSize = strlen(list);
std::cout<<list;
bool isComplete = false;
//Check to see if the last line is complete (i.e. newline terminated)
if(list[size]=='\n') {
isComplete = true;
}
if(GLOBAL_FRAGMENT!=NULL) {
delete[] GLOBAL_FRAGMENT;
}
GLOBAL_FRAGMENT = GLOBAL_FTP->listParse(list,isComplete);
delete[] list;
//We return the length of the new string to prove to libcurl we
//our function properly executed
return size*nmemb;
}
The function above calls the next function to split each line returned into individual
strings to be further processed:
char* FTP::listParse(char* list, bool isComplete) {
//std::cout << list;
//We split the list into seperate lines to deal with independently
char* line = strtok(list,"\n");
int count = 0;
while(line!=NULL) {
count++;
line = strtok(NULL,"\n");
}
//std::cout << "List Count: " << count << "\n";
int curPosition = 0;
for(int i = 0; i < count-1 ; i++) {
//std::cout << "Iteration: " << i << "\n";
curPosition = curPosition + lineParse((char*)&(list[curPosition])) + 1;
}
if(isComplete) {
lineParse((char*)&(list[curPosition]));
return NULL;
} else {
int fraglen = strlen((char*)&(list[curPosition]));
char* frag = new char[fraglen+1];
strcpy(frag,(char*)&(list[curPosition]));
frag[fraglen] = 0;
return frag;
}
}
The function above then calls the function below to split the individual entries in a line into separate tokens:
int FTP::lineParse(char *line) {
int result = strlen(line);
char* value = strtok(line, " ");
while(value!=NULL) {
//std::cout << value << "\n";
value = strtok(NULL, " ");
}
return result;
}
This program works for relatively small list responses but when I tried stress testing it by getting a listing for a remote directory with ~10,000 files in it, my program threw a SIGSEGV... I used backtrace in gdb and found that the segfault happens on lines delete[] GLOBAL_FRAGMENT;' anddelete[] list;inFTP_getList. Am I not properly deleting these arrays? I am callingdelete[]` exactly once for each time I allocate them so I don't see why it wouldn't be allocating memory correctly...
On a side note: Is it necessary to check to see if an array is NULL before you try to delete it?
Also, I know this would be easier to do with STD::Strings but I am trying to learn c style strings as practice, and the fact that it is crashing is a perfect example of why I need practice, I will also be changing the code to store these in a dynamically allocated buffer that only is reallocated when the new ptr size is larger than the previous length, but I want to figure out why the current code isn't working first. :-) Any help would be appreciated.
In this code
size_t listlen = size*nmemb+fraglen+1;
std::cout<<"Size="<<size<<" nmemb="<<nmemb;
char *list = new char[listlen];
if(GLOBAL_FRAGMENT!=NULL) {
snprintf(list,listlen,"%s%s",GLOBAL_FRAGMENT,ptr);
} else {
strncpy(list,ptr,listlen);
}
list[listlen]=0;
You are overruning your list buffer. You have allocated listlen bytes, but you write a 0 value one past the last allocated byte. This invokes undefined behavior. More practically speaking, it can cause heap corruption, which can cause the kind of errors you observed.
I didn't see any issues with the way you are calling delete[].
It is perfectly safe to delete a NULL pointer.
I'm currently working on a class to create and read out packets send through the network, so far I have it working with 16bit and 8bit integers (Well unsigned but still).
Now the problem is I've tried numerous ways of copying it over but somehow the _buffer got mangled, it segfaulted, or the result was wrong.
I'd appreciate if someone could show me a working example.
My current code can be seen below.
Thanks, Xeross
Main
#include <iostream>
#include <stdio.h>
#include "Packet.h"
using namespace std;
int main(int argc, char** argv)
{
cout << "#################################" << endl;
cout << "# Internal Use Only #" << endl;
cout << "# Codename PACKETSTORM #" << endl;
cout << "#################################" << endl;
cout << endl;
Packet packet = Packet();
packet.SetOpcode(0x1f4d);
cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;
packet.add(uint8_t(5))
.add(uint16_t(4000))
.add(uint8_t(5));
for(uint8_t i=0; i<10;i++)
printf("Byte %u = %x\n", i, packet._buffer[i]);
printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
packet.readUint8(),
packet.readUint16(),
packet.readUint8());
return 0;
}
Packet.h
#ifndef _PACKET_H_
#define _PACKET_H_
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
using namespace std;
class Packet
{
public:
Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}
uint16_t GetOpcode() { return m_opcode; }
void SetOpcode(uint16_t opcode) { m_opcode = opcode; }
Packet& add(uint8_t value)
{
if(_buffer.size() < _wpos + 1)
_buffer.resize(_wpos + 1);
memcpy(&_buffer[_wpos], &value, 1);
_wpos += 1;
return *this;
}
Packet& add(uint16_t value)
{
if(_buffer.size() < _wpos + 2)
_buffer.resize(_wpos + 2);
memcpy(&_buffer[_wpos], &value, 2);
_wpos += 2;
return *this;
}
uint8_t readUint8()
{
uint8_t result = _buffer[_rpos];
_rpos += sizeof(uint8_t);
return result;
}
uint16_t readUint16()
{
uint16_t result;
memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));
_rpos += sizeof(uint16_t);
return result;
}
uint16_t m_opcode;
std::vector<uint8_t> _buffer;
protected:
size_t _wpos; // Write position
size_t _rpos; // Read position
};
#endif // _PACKET_H_
Since you're using an std::vector for your buffer, you may as well let it keep track of the write position itself and avoid having to keep manually resizing it. You can also avoid writing multiple overloads of the add function by using a function template:
template <class T>
Packet& add(T value) {
std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
return *this;
}
Now you can write any POD type to your buffer.
implicitly:
int i = 5;
o.write(i);
or explictly:
o.write<int>(5);
To read from the buffer, you will need to keep track of a read position:
template <class T>
T read() {
T result;
uint8_t *p = &_buffer[_rpos];
std::copy(p, p + sizeof(T), (uint8_t*) &result);
_rpos += sizeof(T);
return result;
}
You will need to explicitly pass a type parameter to read. i.e.
int i = o.read<int>();
Caveat: I have used this pattern often, but since I am typing this off the top of my head, there may be a few errors in the code.
Edit: I just noticed that you want to be able to add strings or other non-POD types to your buffer. You can do that via template specialization:
template <>
Packet& add(std::string s) {
add(string.length());
for (size_t i = 0; i < string.length(); ++i)
add(string[i]);
return *this;
}
This tells the compiler: if add is called with a string type, use this function instead of the generic add() function.
and to read a string:
template <>
std::string read<>() {
size_t len = read<size_t>();
std::string s;
while (len--)
s += read<char>();
return s;
}
You could use std::string as internal buffer and use append() when adding new elements.
Thus adding strings or const char* would be trivial.
Adding/writing uint8 can be done with casting it to char, writing uint16 - to char* with length sizeof(uint16_t).
void write_uint16( uint16_t val )
{
m_strBuffer.append( (char*)(&var), sizeof(val) );
}
Reading uint16:
uint16_t read_int16()
{
return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}
You appear to be attempting to print ten bytes out of the buffer when you've only added four, and thus you're running off the end of the vector. This could be causing your seg fault.
Also your printf is trying to print a character as an unsigned int with %x. You need to use static_cast<unsigned>(packet._buffer[i]) as the parameter.
Stylistically:
Packet packet = Packet(); could potentially result in two objects being constructed. Just use Packet packet;
Generally try to avoid protected attributes (protected methods are fine) as they reduce encapsulation of your class.