HeapValidation Error

I'm trying to callback using a pointer to a base type, but something along the way is giving me a HeapValidation error.
But I have no idea where it's messing up. What the hell am I not doing correctly?


Allow me to explain...
This is the "Event" base structure, which just contains an integer "code" to discern which event type it is.
1
2
3
4
5
6
7
struct Event {
	static const char Leave = 1;

	int code = 0;
	Event(int code) : code(code) { }
	virtual ~Event() { }
};


This is the "Leave" event, which extends Event and contains "Player" object...
1
2
3
4
5
6
struct Leave : Event {
	Player player;

	Leave(Player p) : Event(Event::Leave), player(p) { }
	~Leave() { }
};


These are the globals, to make this more readable I just took the "players" map and relevant methods from the "World" class.
1
2
std::map<uint32_t, Player> players;
bool(__cdecl* callback)(game::Event*) = nullptr;


These are the relevant methods from "World"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ID is a macro for "id + 1"
Player & make_player(uint32_t id) {
	players[ID] = Player(ID, "");
	return players[ID];
}

Player & make_player() {
	return make_player(0);
}

Player & find_player(uint32_t id) {
	if (players.find(ID) == players.end())
		return make_player(ID);
	return player;
}


This may require more explanation, so feel free to ask. The following two methods are to get a reference of the player in the "players" map. It performs a macro called "PARAM_CHECK" which is just to see if the "Parameters" map (uint8_t key, Value* value) contains the key "i" and if that Value* is of the correct type code. If the parameters map does not contain the value, it will just return 0, so we reference the 0th key of the "players" map, like above. Otherwise, we return a reference to the player in the players map.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// uint32_t template specialization
template<>
uint32_t get_num(Parameters* params, int i) {
	if (!PARAM_CHECK(i, TypeCode::Integer))
		return 0;
	
	// big_endian <- &ptr <- TypedValue* <- Value*
	TypedValue* val = (TypedValue*)(*params)[i];
	return htonl(*((uint32_t*)&val->ptr));
}

Player& get_player(Parameters* params, int i) {
	if (!PARAM_CHECK(i, TypeCode::Integer))
		return make_player(); // default to possible saved data we have
	uint32_t id = get_num<uint32_t>(params, i);
	return find_player(id);
}



Finally, we have these two methods, which are to discern the type of the event (code), and create the Event object (Leave in the first case), then pass it to dispatch to perform the callback. I originally intended for this to be an async call so it wouldn't block, but I keep getting this damn HeapValidation error, so I'm simplifying it for now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void dispatch(Event& event) {
	callback(&event);
}

bool _dispatch_event(uint16_t code, Parameters* params) {
	Player& source = get_player(params, 0);
	switch (code) {
	case MessageCode::Events::Leave: {
		print("Leave Dispatched.");
		Leave event(source);
		dispatch(static_cast<Event&>(event));
		break;
	}
        ...
        }
}


That should be all the code necessary, feel free to ask if you need more information. The problem is that I don't know, necessarily, what a HeapValidation error is. I assume it's because I'm making a call to callback and the heap is not the correct size or maybe it's a different address than was intended, and that's what is throwing the error, but I genuinely have no clue.
Last edited on
While the exact issue isn't obvious, the error does suggest that you are basically trashing some memory somewhere.

Using a variable to identify what kind of object something is seems wrong. The whole point of inheritance is that the objects behave correctly based on what they are, just by existing.

return htonl(*((uint32_t*)&val->ptr));
All this manual C style casting feels wrong and dangerous. This is C++.

Can you not use a std::function or other such, if you need callbacks?
Last edited on
1
2
Leave event(source);
dispatch(static_cast<Event&>(event));


This also doesn't look right. If the dispatch function accepts an object of type Event, then the cast looks wrong. event already is an object of type Event, because a Leave object IS an object of type Event.

Does dispatch accept the object by reference? Hope there's no threading going on there and that the dispatch function blocks, because the Leave object being referred to will cease to exist when _dispatch_event finishes.


1
2
3
void dispatch(Event& event) {
	callback(&event);
}

I see that callback then uses a pointer to the Event object... does that callback block? If that doesn't block, the object is about to vanish just as it's using it...
Last edited on
> That should be all the code necessary
provide enough code to reproduce your issue
can't compile the snips you've posted


debugger, backtrace
also, may use valgrind or similar
I found this:
1
2
3
4
5
Player & find_player(uint32_t id) {
	if (players.find(ID) == players.end())
		return make_player(ID);
	return player;  // should be return players[id];
}

Of course, the iterator is already pointing the right element, so if you stored it, you could just dereference that pointer rather than doing another binary search.

But I've can't see anything else wrong with what you've posted. However, passing Parameters* around like that is something I wouldn't do.

If you've done any Windows SDK programming, you'll see they have to pack all sorts of things into WPARAMs and LPARAMs, but they don't pass those around. At the point of reception, they convert to the real data type and from then on use that.
Last edited on
Topic archived. No new replies allowed.