There doesn't seem to be a problem with the At pointer, as it's never modified in the ParseOBJ function.
At->Content->Data points to garbage data after parsing the file because when you Pop a token you advance that pointer. At the end of the loop it's expected that it would point 1 byte past the end of the valid data. The garbage data is whatever was in memory before you used it to read the file. If there was a 0 after the file content (you could for instance make your file reading function add a zero at the end) the debugger would stop showing the garbage as it would consider that a null terminated string.
It's a personal choice but instead of using a counter, I like to write those loops like this:
| uint8_t* current = At->Content->Data;
uint8_t* end = current + At->Content->Count;
while ( current < end ) { /* The loop ends when the current pointer is past the end pointer. */
...
}
|
To avoid casting to char* you could change you FBuffer struct to be
| struct FBuffer
{
umm Count;
union {
u8* Data;
char* Text;
};
};
|
Your PopToken function could just return a FBuffer since you don't seem to use the "value" part of the Token.
The following code could potentially read invalid memory if the file was corrupted (but maybe you can trust file and don't care about that), since you don't test for the length of the token before using it: if the file was truncated it would return a token with the data pointer after the end of the valid data and a count of 0.
| Vertices[VertexCount++] = vec3{
strtof((char*)PopToken(&At->Contents).Text.Data, 0),
strtof((char*)PopToken(&At->Contents).Text.Data, 0),
strtof((char*)PopToken(&At->Contents).Text.Data, 0)
};
|