Very new to C++ and having problems returning a vector. I put a breakpoint and the array is correct (populated with all the objects I would expect from the query). But when it returns I get an error:
EXC_BAD_ACCESS
on line m_pComponentContainer->removeAll();
from CCNode.cpp
Which is strange since this is a base class (does NOT inherit from any kind of CC object) although I am extensively using the Cocos2dx framework, its not included in this class.
Im fairly sure this is because something is being deallocated. However like I said Im very new to C++ and not really sure where the problem is. I was hoping to get a little further in development before I had to start worrying about memory management.
int numberOfCards = DatabaseHelper::getNumberOfCards();
//cant be zero
assert(numberOfCards);
std::vector<CardSlot> returnArray(numberOfCards);
sqlite3_stmt * statement;
if (sqlite3_open(this->dbpath.c_str(),&this->cardWarsDB) == SQLITE_OK)
{
const char* query_stmt = "select ID, HP, MP, AbilityText from Cards WHERE ID IN (SELECT DISTINCT cardsID FROM Deck WHERE name = 'All')";
if (sqlite3_prepare_v2(this->cardWarsDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
CardSlot *aCard;
const char* cardID = (const char*)sqlite3_column_text(statement, 0);
const char* cardHP = (const char*)sqlite3_column_text(statement, 1);
const char* cardMP = (const char*)sqlite3_column_text(statement, 2);
const char* cardAbility = (const char*)sqlite3_column_text(statement, 3);
if (cardID != NULL) {
std::string imageName = ".png";
imageName = cardID + imageName;
aCard = (CardSlot *)CardSlot::spriteWithFile(imageName.c_str());
}
if (cardID != NULL) {
aCard->cardID = std::string(cardID);
cocos2d::CCLog("DB returned results, cardID: %s",aCard->cardID.c_str());
}
if (cardHP != NULL) {
aCard->cardHP = std::string(cardHP);
cocos2d::CCLog("DB returned results, cardHP: %s",aCard->cardHP.c_str());
}
if (cardMP != NULL) {
aCard->cardMP = std::string(cardMP);
cocos2d::CCLog("DB returned results, cardMP: %s",aCard->cardMP.c_str());
}
if (cardAbility != NULL) {
aCard->cardAbility = std::string(cardAbility);
cocos2d::CCLog("DB returned results, cardAbility: %s",aCard->cardAbility.c_str());
}
numberOfCards--;
returnArray[numberOfCards] = *aCard;
}
sqlite3_finalize(statement);
}
sqlite3_close(this->cardWarsDB);
return returnArray;
}
Here is a screenshot of the stack trace. I was just looking at it, and it seems that it is the CardSlot objects are the culprits.
But still dont know how to "retain" them, but Ill look at some Cocos documentation.
NOTE1
It looks like your CardSlot is not safe to copy. You copy CardSlots in at least two places:
aCard = * CardSlot::spriteWithFile(imageName.c_str()); (also a memory leak assuming spriteWithFile returns CardSlot *; the "temporary" is not destructed)
returnArray[numberOfCards] = aCard;
From what I can tell, you are probably keeping a CCSprite pointer in CardSlot and destroying it (with delete) in your CardSlot destructor. However, this pointer gets destroyed multiple times because of the copies, which causes your crash.
You need to redesign your class so it can either be safely copied, or refactor your code so that you make no copies (e.g. by using a vector<shared_ptr<CardSlot> > to hold pointers to the instances).
I have edited the code to use more pointers rather then passing around and filling my array with objects. However I think a big thing that helped fix it was using cocos2d::CCArray instead of a std::vector. Most of my classes are children of Cocos2d classes (CCSprites, and CCLayers) and so using its own array data type makes sense.
cocos2d::CCArray DatabaseHelper::getAllCards()
{
int numberOfCards = DatabaseHelper::getNumberOfCards();
//cant be zero
assert(numberOfCards);
cocos2d::CCArray returnArray(numberOfCards);
sqlite3_stmt * statement;
if (sqlite3_open(this->dbpath.c_str(),&this->cardWarsDB) == SQLITE_OK)
{
const char* query_stmt = "select ID, HP, MP, AbilityText from Cards WHERE ID IN (SELECT DISTINCT cardsID FROM Deck WHERE name = 'All')";
if (sqlite3_prepare_v2(this->cardWarsDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
CardSlot* aCard;
const char* cardID = (const char*)sqlite3_column_text(statement, 0);
const char* cardHP = (const char*)sqlite3_column_text(statement, 1);
const char* cardMP = (const char*)sqlite3_column_text(statement, 2);
const char* cardAbility = (const char*)sqlite3_column_text(statement, 3);
if (cardID != NULL) {
std::string imageName = ".png";
imageName = cardID + imageName;
aCard = CardSlot::spriteWithFile(imageName.c_str());
}
if (cardID != NULL) {
aCard->cardID = std::string(cardID);
cocos2d::CCLog("DB returned results, cardID: %s",aCard->cardID.c_str());
}
if (cardHP != NULL) {
aCard->cardHP = std::string(cardHP);
cocos2d::CCLog("DB returned results, cardHP: %s",aCard->cardHP.c_str());
}
if (cardMP != NULL) {
aCard->cardMP = std::string(cardMP);
cocos2d::CCLog("DB returned results, cardMP: %s",aCard->cardMP.c_str());
}
if (cardAbility != NULL) {
aCard->cardAbility = std::string(cardAbility);
cocos2d::CCLog("DB returned results, cardAbility: %s",aCard->cardAbility.c_str());
}
numberOfCards--;
returnArray.addObject(aCard);
}
sqlite3_finalize(statement);
}
sqlite3_close(this->cardWarsDB);
return returnArray;
}
//incase sql fails, close db and created a "FAILED" card
sqlite3_close(this->cardWarsDB);
cocos2d::CCLog("DB returned error: cant open char catagories file");
cocos2d::CCArray failedReturnArray(1);
CardSlot * aCard;
aCard->cardID = std::string("FAILED");
aCard->cardHP = std::string("FAILED");
aCard->cardMP = std::string("FAILED");
aCard->cardAbility = std::string("FAILED");
failedReturnArray.addObject(aCard);
return failedReturnArray;
}
Also in case anyone cares here is CardSlot (not much to it, only built the constructor at this time):
CardSlot * CardSlot::spriteWithFile(const char *pszFileName)
{
CCLOG("CardSlot::spriteWithFile");
CardSlot * aCard = new CardSlot();
if (aCard && aCard->initWithFile(pszFileName))
{
aCard->cardID = pszFileName;
aCard->scheduleUpdate();
aCard->autorelease();
return aCard;
}
CC_SAFE_DELETE(aCard);
return NULL;
}
The only thing Im concerned about is that I think my CCArray should be a pointer. But its working now and learning all the memory management "tricks of the trade" will come in time, the more I work with C++
Thanks #nneonneo for all the help Im sure your fix would have worked and I tried but no matter what I did couldnt get the vector to work. I 1up'd you as much as I could but really this is the "Answer" I implemented.
The returnArray is declared local to the function, it will be deallocated when the function returns. You would need to either declare it as static or move the declaration to outside the function.
Related
while working with those function i'm getting stuck with an error.
The debbuger says "damged heap" on _chdir(dirCorrente); line.
The main calls those function as follow:
- char* temp = getCartellaCorrente();
- some other stuff not relative to these function...
- temp = setCartellaCorrente("cd test")
when the execution stops the setCartellaCorrente's dirCorrente value is '"C:\Users\Luca\Desktop\remote-control-project\FirstService\Debug\test"'
I think i'm doing something wrong with dynamically allocated variables.
I'm working on this problem since 48 hours now, i've serached on the internet but nothing. I guess that i don't know something important about allocated variable or _chdir function.
I will be really gratefull if you can explain me what i miss.
char* getCartellaCorrente() {
char* temp;
size_t size;
LPWSTR dirCorrente = new TCHAR[DEFAULT_BUFLEN];
GetCurrentDirectory(DEFAULT_BUFLEN, dirCorrente);
size = wcslen(dirCorrente);
temp = (char *)malloc(size);
wcstombs_s(NULL, temp, size+1, dirCorrente, size);
return temp;
}
char* setCartellaCorrente(char* relative) {
char *dirCorrente;
if (strlen(relative)>=5 && relative[4] == ':') {
dirCorrente = (char *)malloc(DEFAULT_BUFLEN);
strcpy_s(dirCorrente, DEFAULT_BUFLEN, &relative[3]);
}
else {
dirCorrente = getCartellaCorrente();
relative[2] = '\\';
strcat_s(dirCorrente, DEFAULT_BUFLEN, &relative[2]);
printf("goode %s \n", dirCorrente);
}
//fixPathSlash(dirCorrente);
printf("\n2: %s\n", dirCorrente);
int i = _chdir(dirCorrente); //HERE IT STOPS
printf("wtf: %d\n", i);
free(dirCorrente);
printf("boh\n");
return getCartellaCorrente();
}
It's my first question. Sorry if i missed some important information, i'll edit fast.
Ok i managed to solve the problem, as i thoght the problem was the allocation.
Since i need to solve this fast for now i've used the method i listed above, anyway i will study how to work with allocated variable and modify it to improve it.
void getCartellaCorrente(char* temp) {
size_t size;
LPWSTR dirCorrente = new TCHAR[DEFAULT_BUFLEN];
GetCurrentDirectory(DEFAULT_BUFLEN, dirCorrente);
size = wcslen(dirCorrente);
wcstombs_s(NULL, temp, DEFAULT_BUFLEN, dirCorrente, size);
}
void setCartellaCorrente(char* relative, char* dirCorrente) {
if (strlen(relative)>=5 && relative[4] == ':') {
strcpy_s(dirCorrente, DEFAULT_BUFLEN, &relative[3]);
}
else {
getCartellaCorrente(dirCorrente);
relative[2] = '\\';
strcat_s(dirCorrente, DEFAULT_BUFLEN, &relative[2]);
}
int i = _chdir(dirCorrente);
return getCartellaCorrente(dirCorrente);
}
The path variable is now allocated into the main with static size, the functions does not return the correct value, instead they change it directly.
I have the following code here that executes a query. Originally, I used SQL Injection to return row results. Hearing I should use parametrization, I rearranged my code and read the MySQL docs on how to do so. I'm using MySQL's C library in a C++ application.
However, it's not returning the results.
I know my SQL statement is 100% fine. It has been tested. The only thing I changed was changing %d (injection) to ?, which accepts the player's ID.
This returns -1. It's a SELECT statement though, so maybe it's normal?
// Get the number of affected rows
affected_rows = mysql_stmt_affected_rows(m_stmt);
This returns 2. This is correct. I have two fields being returned.
// Store the field count
m_fieldCount = mysql_field_count(&m_conn);
This returns 0 (success)
if (mysql_stmt_store_result(m_stmt))
Finally, this returns null.
m_result = mysql_store_result(&m_conn);
I need m_result so I can read the rows. "mysql_stmt_store_result" sounds similar, but doesn't return MYSQL_RESULT.
m_result = mysql_store_result(&m_conn);
/// <summary>
/// Executes a query.
/// </summary>
/// <param name="query">The query to execute.</param>
/// <returns>Returns true on success, else false.</returns>
bool SQLConnection::executeQuery_New(const char *query)
{
int param_count = 0;
int affected_rows = 0;
// Validate connection.
if (!m_connected)
return false;
// Initialize the statement
m_stmt = mysql_stmt_init(&m_conn);
if (!m_stmt) {
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
return false;
}
// Prepare the statement
if (mysql_stmt_prepare(m_stmt, query, strlen(query))) {
fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(m_stmt));
return false;
}
// Get the parameter count from the statement
param_count = mysql_stmt_param_count(m_stmt);
if (param_count != m_bind.size()) {
fprintf(stderr, " invalid parameter count returned by MySQL\n");
return false;
}
// Bind buffers
// The parameter binds are stored in std::vector<MYSQL_BIND>
// I need to convert std::vector<MYSQL_BIND> m_bind to MYSQL_BIND *bnd
MYSQL_BIND *bind = new MYSQL_BIND[m_bind.size() + 1];
memset(bind, 0, sizeof(bind) * m_bind.size());
for (int i = 0; i < param_count; i++)
bind[i] = m_bind[i];
if (mysql_stmt_bind_param(m_stmt, &bind[0]))
{
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(m_stmt));
return false;
}
// Execute the query
if (mysql_stmt_execute(m_stmt)) {
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(m_stmt));
return false;
}
// Get the number of affected rows
affected_rows = mysql_stmt_affected_rows(m_stmt);
//if (affected_rows == -1) {
// fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
// fprintf(stderr, " %s\n", mysql_stmt_error(m_stmt));
// return false;
//}
// Store the field count
m_fieldCount = mysql_field_count(&m_conn);
// Store the result
if (mysql_stmt_store_result(m_stmt))
{
fprintf(stderr, " failed retrieving result\n");
fprintf(stderr, " %s\n", mysql_error(&m_conn));
int d = mysql_errno(&m_conn);
return false;
}
// This looks similar to the last above statement, but I need m_result. I used mysql_store_result earlier when using injection and it worked fine, but here in this case it returns null.
m_result = mysql_store_result(&m_conn);
// Close the statement
if (mysql_stmt_close(m_stmt)) {
/* mysql_stmt_close() invalidates stmt, so call */
/* mysql_error(mysql) rather than mysql_stmt_error(stmt) */
fprintf(stderr, " failed while closing the statement\n");
fprintf(stderr, " %s\n", mysql_error(&m_conn));
return false;
}
// Delete bind array
if (bind) {
delete[] bind;
bind = NULL;
}
return true;
}
How I'm adding an int parameter (player's id):
void SQLConnection::addParam(int buffer, enum_field_types type, unsigned long length)
{
MYSQL_BIND bind;
memset(&bind, 0, sizeof(bind));
bind.buffer = (char *)&buffer;
bind.buffer_type = type;
bind.is_null = 0;
bind.length = &length;
m_bind.push_back(bind);
}
My variables and their types:
class SQLConnection
{
private:
MYSQL m_conn;
MYSQL_ROW m_row;
MYSQL_RES *m_result;
char m_errorMessage[ERROR_MSG_MAX];
bool m_connected;
MYSQL_STMT *m_stmt;
std::vector<MYSQL_BIND> m_bind;
int m_fieldCount;
// ...
And finally its calling function at the end of the SQL statement:
...WHERE player_id = ?;");
conn.addParam(m_id, MYSQL_TYPE_LONGLONG, 0);
if (!conn.executeQuery_New(buffer)) {
conn.close();
return "";
}
// Close the connection.
conn.close();
std::string s = conn.getField("max_value_column_name");
The error code I get is 2014:
https://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html
Just for the sake of interest, this is a prior function I used. This worked fine for injection. Using the new function above with parameterization is the one causing the issues.
bool SQLConnection::executeQuery(const char *query)
{
// Validate connection.
if (!m_connected)
return false;
// Execute the query
int status = mysql_query(&m_conn, query);
if (status != 0) {
sprintf(m_errorMessage, "Error: %s", mysql_error(&m_conn));
return false;
}
// Store the result
m_result = mysql_store_result(&m_conn);
return true;
}
After I started having language religious wars in my head about using C# over C++, I thought I'd give one last attempt here. Any help is appreciated.
Edit:
This is how I read in column names prior to parameterization (maybe this code needs to be updated after calling mysql_stmt_store_result(m_stmt)?
std::string SQLConnection::getField(const char *fieldName)
{
MYSQL_FIELD *field = NULL;
unsigned int name_field = 0;
mysql_stmt_data_seek(m_stmt, 0);
mysql_stmt_fetch_column(m_stmt, &bind, 0, 0);
//mysql_data_seek(m_result, 0);
//mysql_field_seek(m_result, 0);
const unsigned int num_fields = mysql_stmt_field_count(m_stmt);
// const unsigned int num_fields = mysql_num_fields(m_result);
std::vector<char *> headers(num_fields);
for (unsigned int i = 0; (field = mysql_fetch_field(m_result)); i++)
{
headers[i] = field->name;
if (strcmp(fieldName, headers[i]) == 0)
name_field = i;
}
while ((m_row = mysql_fetch_row(m_result))) {
return std::string(m_row[name_field]);
}
return "";
}
Edit:
What I'm finding is in this last function there are equivalent functions for statements, like mysql_num_fields() is mysql_stmt_field_count(). I'm thinking these need to be updated because it's using m_stmt and not m_result anymore, which gives reason to update the functions so m_stmt is used. It's not very apparent how to update the second half of the function though.
You may need a better understanding of how stmt works.You can't get the final results by mysql_store_result() when you're using stmt.
You shoud bind several buffers for the statement you're using to accept the result set. You can finish this by mysql_stmt_bind_result(), just like mysql_stmt_bind_param().
Then you can use the buffers bound by mysql_stmt_bind_result() to return row data. You can finish this by mysql_stmt_fetch().
Do the fetch method repeatedly, so you can get the whole result set row by row.
The basic sequence of calls:
mysql_stmt_init
mysql_stmt_prepare
mysql_stmt_bind_param
mysql_stmt_execute
mysql_stmt_bind_result
mysql_stmt_store_result
mysql_stmt_fetch (repeatedly, row by row)
mysql_stmt_free_result
It works for me.
It's a long time since I finished this part of my project, you'd better read the manual carefully and find more examples of stmt.
Sorry for my poor English. Good luck!
How to correct return created std::list through function argument? Now, I try so:
bool DatabaseHandler::tags(std::list<Tag> *tags)
{
QString sql = "SELECT * FROM " + Tag::TABLE_NAME + ";";
QSqlQueryModel model;
model.setQuery(sql);
if(model.lastError().type() != QSqlError::NoError) {
log(sql);
tags = NULL;
return false;
}
const int count = model.rowCount();
if(count > 0)
tags = new std::list<Tag>(count);
else
tags = new std::list<Tag>();
//some code
return true;
}
After I can use it:
std::list<Tag> tags;
mDB->tags(&tags);
Now, I fix my function:
bool DatabaseHandler::tags(std::list<Tag> **tags)
{
QString sql = "SELECT * FROM " + Tag::TABLE_NAME + ";";
QSqlQueryModel model;
model.setQuery(sql);
if(model.lastError().type() != QSqlError::NoError) {
log(sql);
*tags = NULL;
return false;
}
const int count = model.rowCount();
if(count > 0)
*tags = new std::list<Tag>(count);
else
*tags = new std::list<Tag>();
for(int i = 0; i < count; ++i) {
auto record = model.record(i);
Tag tag(record.value(Table::KEY_ID).toInt());
(*tags)->push_back(tag);
}
return true;
}
It works but list return size 4 although loop executes only 2 iterations and empty child objects (if I just called their default constructor). The Tag class hasn't copy constructor.
Since you passed an already instantiated list as a pointer to the function, there is no need to create another list.
In that sense, you question is pretty unclear. I'd suggest you read up a bit on pointers, references and function calls in general.
http://www.cplusplus.com/doc/tutorial/pointers/
http://www.cplusplus.com/doc/tutorial/functions/
UPDATE: I still strongly suggest you read up on the mentioned topics, since you don't know these fundamental points.
Anyway, this is what you probably want to do (event though I would suggest using references, here is the solution with pointers):
bool someFunc(std::list<Tag> **tags) {
// by default null the output argument
*tags = nullptr;
if (error) {
return false;
}
// dereference tags and assign it the address to a new instance of list<Tag>
*tags = new std::list<Tag>();
return true
}
std::list<Tag> *yourList;
if (someFunc(&yourList)) {
// then yourList is valid
} else {
// then you had an error and yourList == nullptr
}
However, this is not idiomatic C++. Please read a modern book or tutorial.
Use a reference.
bool DatabaseHandler::tags(std::list<Tag>& tags);
std::list<Tag> tags;
mDB->tags(tags);
You'll have to change all the -> to ., of course. Every operation done on the reference in the function will be done to the original tags list it was called with.
EDIT: If you want to create the list inside the function and return it, you have a couple options. The closest, I think, is to just return a list pointer, and return nullptr if the function fails.
//beware, pseudocode ahead
std::list<Tag>* DatabaseHandler::tags() //return new list
{
if (success)
return new std::list<Tag>(...); //construct with whatever
else
return nullptr; //null pointer return, didn't work
}
std::list<Tag> tags* = mDB->tags();
You could alternatively have it return an empty list instead, depending on how you want it to work. Taking a reference to a pointer would work the same way, too.
bool DatabaseHandler::tags(std::list<Tag>*&); //return true/false
std::list<Tag>* tags;
mDB->tags(tags); //tags will be set to point to a list if it worked
The following code works in a the Marmalade simulator (I'm on OSX using x-code)
bool PictureDictionary::OnTableSelect(CTable* table, int tab){
//if something is selected, look up the item, and display it
//also change the search to the selected item
if(-1 < tab){
// if a term is selected, set the search text field to the term
CString term = m_SearchResults.GetString(tab);
if(m_currentWord != (char*)term.Get()){
m_currentWord = (char *)term.Get();
m_searchTextField->SetAttribute("text", term);
char* normalizedTerm = (char *)term.Get();
char* imagePath;
sprintf(imagePath,"images/%s.jpg", normalizedTerm);
if(m_ImageAttached){
m_Image->SetAttribute("image", (const char*)imagePath);
} else {
m_Image = CreateImage(CAttributes()
.Set("name", "picture")
.Set("x1", "0")
.Set("x2", "0")
.Set("y1", "50%")
.Set("image", (const char*)imagePath)
);
m_SearchView->AddChild(m_Image);
m_ImageAttached = true;
}
}
}
return true;
}
When I run the simulator, and select an item from the table, the image appears, and changes when I select a different item. When I go to refactor, I get a EXC_BAD_ACCESS (code=1…..) Error
bool PictureDictionary::OnTableSelect(CTable* table, int tab){
//if something is selected, look up the item, and display it
//also change the search to the selected item
if(-1 < tab){
// if a term is selected, set the search text field to the term
CString term = m_SearchResults.GetString(tab);
if(m_currentWord != (char*)term.Get()){
m_currentWord = (char *)term.Get();
m_searchTextField->SetAttribute("text", term);
char* normalizedTerm = (char *)term.Get();
char* imagePath;
sprintf(imagePath,"images/%s.jpg", normalizedTerm);
UpdatePictureView(imagePath);
}
}
return true;
}
void PictureDictionary::UpdatePictureView(char* imagePath){
if(m_ImageAttached){
m_Image->SetAttribute("image", (const char*)imagePath);
} else {
m_Image = CreateImage(CAttributes()
.Set("name", "picture")
.Set("x1", "0")
.Set("x2", "0")
.Set("y1", "50%")
.Set("image", (const char*)imagePath)
);
m_SearchView->AddChild(m_Image);
m_ImageAttached = true;
}
}
Any suggestions on how to clean up the code without getting these issues?
Edit RE Comments about uninitialized variables:
m_ImageAttached was initialized to false in the constructor, unless I'm doing something wrong. Also, changing the condition to check if m_Image!=NULL also throws the same error.
main.cpp:
PictureDictionary pictDict(myApp, &dictionary);
Constructor for PictureDictionary:
PictureDictionary::PictureDictionary(CAppPtr app,Dictionary::Dictionary* dictionary){
m_App = app;
m_Dictionary = dictionary;
m_currentWord = "";
m_ImageAttached = false;
}
imagePath is an unitialized pointer, in both snippets. Any attempt to dereference is undefined behaviour. It just appeared to work in the first snippet. Use an array or populate a std::string instead:
std::string imagePath(std::string("images/") + normalizedTerm + ".jpg");
And use std::string::c_str() if access to the underlying const char* is required.
I have a situation in Visual C++ 2008 that I have not seen before. I have a class with 4 STL objects (list and vector to be precise) and integers.
It has a method:
inline int id() { return m_id; }
The return value from this method is corrupt, and I have no idea why.
debugger screenshot http://img687.imageshack.us/img687/6728/returnvalue.png
I'd like to believe its a stack smash, but as far as I know, I have no buffer over-runs or allocation issues.
Some more observations
Here's something that puts me off. The debugger prints right values in the place mentioned // wrong ID.
m_header = new DnsHeader();
assert(_CrtCheckMemory());
if (m_header->init(bytes, size))
{
eprintf("0The header ID is %d\n", m_header->id()); // wrong ID!!!
inside m_header->init()
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
eprintf("The details are %d,%d,%d,%d\n", m_qdcount, m_ancount, m_nscount, m_arcount);
// copy the flags
// this doesn't work with a bitfield struct :(
// memcpy(&m_flags, bytes + 2, sizeof(m_flags));
//unpack_flags(bytes + 2); //TODO
m_init = true;
}
eprintf("Assigning an id of %d\n", m_id); // Correct ID.
return
m_header->id() is an inline function in the header file
inline int id() { return m_id; }
I don't really know how best to post the code snippets I have , but here's my best shot at it. Please do let me know if they are insufficient:
Class DnsHeader has an object m_header inside DnsPacket.
Main body:
DnsPacket *p ;
p = new DnsPacket(r);
assert (_CrtCheckMemory());
p->add_bytes(buf, r); // add bytes to a vector m_bytes inside DnsPacket
if (p->parse())
{
read_packet(sin, *p);
}
p->parse:
size_t size = m_bytes.size(); // m_bytes is a vector
unsigned char *bytes = new u_char[m_bytes.size()];
copy(m_bytes.begin(), m_bytes.end(), bytes);
m_header = new DnsHeader();
eprintf("m_header allocated at %x\n", m_header);
assert(_CrtCheckMemory());
if (m_header->init(bytes, size)) // just set the ID and a bunch of other ints here.
{
size_t pos = DnsHeader::SIZE; // const int
if (pos != size)
; // XXX perhaps generate a warning about extraneous data?
if (ok)
m_parsed = true;
}
else
{
m_parsed = false;
}
if (!ok) {
m_parsed = false;
}
return m_parsed;
}
read_packet:
DnsHeader& h = p.header();
eprintf("The header ID is %d\n", h.id()); // ID is wrong here
...
DnsHeader constructor:
m_id = -1;
m_qdcount = m_ancount = m_nscount = m_arcount = 0;
memset(&m_flags, 0, sizeof(m_flags)); // m_flags is a struct
m_flags.rd = 1;
p.header():
return *m_header;
m_header->init: (u_char* bytes, int size)
header_fmt *h = (header_fmt *)bytes;
m_id = ntohs(h->id);
eprintf("Assigning an id of %d/%d\n", ntohs(h->id), m_id); // ID is correct here
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
You seem to be using a pointer to an invalid class somehow. The return value shown is the value that VS usually uses to initialize memory with:
2^32 - 842150451 = 0xCDCDCDCD
You probably have not initialized the class that this function is a member of.
Without seeing more of the code in context.. it might be that the m_id is out of the scope you expect it to be in.
Reinstalled VC++. That fixed everything.
Thank you for your time and support everybody! :) Appreciate it!