Skip to content

Instantly share code, notes, and snippets.

@zachreizner
Created March 29, 2025 15:58
Show Gist options
  • Save zachreizner/ea0f24ff0fc5c9b3206f4fa406cff437 to your computer and use it in GitHub Desktop.
Save zachreizner/ea0f24ff0fc5c9b3206f4fa406cff437 to your computer and use it in GitHub Desktop.
CnC Generals AsciiString
void AsciiString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveData, const char* strToCopy, const char* strToCat)
{
validate();
if (m_data &&
m_data->m_refCount == 1 &&
m_data->m_numCharsAllocated >= numCharsNeeded)
{
// no buffer manhandling is needed (it's already large enough, and unique to us)
if (strToCopy)
strcpy(m_data->peek(), strToCopy);
if (strToCat)
strcat(m_data->peek(), strToCat);
return;
}
int minBytes = sizeof(AsciiStringData) + numCharsNeeded*sizeof(char);
if (minBytes > MAX_LEN)
throw ERROR_OUT_OF_MEMORY;
int actualBytes = TheDynamicMemoryAllocator->getActualAllocationSize(minBytes);
AsciiStringData* newData = (AsciiStringData*)TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_AsciiString::ensureUniqueBufferOfSize");
newData->m_refCount = 1;
newData->m_numCharsAllocated = (actualBytes - sizeof(AsciiStringData))/sizeof(char);
#if defined(_DEBUG) || defined(_INTERNAL)
newData->m_debugptr = newData->peek(); // just makes it easier to read in the debugger
#endif
if (m_data && preserveData)
strcpy(newData->peek(), m_data->peek());
else
newData->peek()[0] = 0;
// do these BEFORE releasing the old buffer, so that self-copies
// or self-cats will work correctly.
if (strToCopy)
strcpy(newData->peek(), strToCopy);
if (strToCat)
strcat(newData->peek(), strToCat);
releaseBuffer();
m_data = newData;
validate();
}
class AsciiString
{
private:
// Note, this is a Plain Old Data Structure... don't
// add a ctor/dtor, 'cuz they won't ever be called.
struct AsciiStringData
{
#if defined(_DEBUG) || defined(_INTERNAL)
const char* m_debugptr; // just makes it easier to read in the debugger
#endif
unsigned short m_refCount; // reference count
unsigned short m_numCharsAllocated; // length of data allocated
// unsigned int m_padding;
// char m_stringdata[];
inline char* peek() { return (char*)(this+1); }
};
#ifdef _DEBUG
void validate() const;
#else
inline void validate() const { }
#endif
protected:
AsciiStringData* m_data; // pointer to ref counted string data
Breakpoint 1, AsciiString::ensureUniqueBufferOfSize (this=0x7fffffffd080, numCharsNeeded=5, preserveData=false, strToCopy=0x555555dc6691 "None", strToCat=0x0) at /data/scratch/CnC/Generals/Code/GameEngine/Source/Common/System/AsciiString.cpp:126
126 validate();
(gdb) n
128 if (m_data &&
(gdb)
140 int minBytes = sizeof(AsciiStringData) + numCharsNeeded*sizeof(char);
(gdb) p minBytes
$1 = 0
(gdb) n
141 if (minBytes > MAX_LEN)
(gdb) p minBytes
$2 = 21
(gdb) n
144 int actualBytes = TheDynamicMemoryAllocator->getActualAllocationSize(minBytes);
(gdb)
145 AsciiStringData* newData = (AsciiStringData*)TheDynamicMemoryAllocator->allocateBytesDoNotZero(actualBytes, "STR_AsciiString::ensureUniqueBufferOfSize");
(gdb) p actualBytes
$3 = 32
(gdb) n
146 newData->m_refCount = 1;
(gdb) p newData
$4 = (AsciiString::AsciiStringData *) 0x7ffff6e92370
(gdb) n
147 newData->m_numCharsAllocated = (actualBytes - sizeof(AsciiStringData))/sizeof(char);
(gdb) p newData
$5 = (AsciiString::AsciiStringData *) 0x7ffff6e92370
(gdb) p *newData
$6 = {m_debugptr = 0x0, m_refCount = 1, m_numCharsAllocated = 0}
(gdb) n
149 newData->m_debugptr = newData->peek(); // just makes it easier to read in the debugger
(gdb) p *newData
$7 = {m_debugptr = 0x0, m_refCount = 1, m_numCharsAllocated = 16}
(gdb) n
152 if (m_data && preserveData)
(gdb) p *newData
$8 = {m_debugptr = 0x7ffff6e92374 "\377\177", m_refCount = 1, m_numCharsAllocated = 16}
(gdb) n
155 newData->peek()[0] = 0;
(gdb) p *newData
$9 = {m_debugptr = 0x7ffff6e92374 "\377\177", m_refCount = 1, m_numCharsAllocated = 16}
(gdb) n
159 if (strToCopy)
(gdb) p *newData
$10 = {m_debugptr = 0x7f00f6e92374 <error: Cannot access memory at address 0x7f00f6e92374>, m_refCount = 1, m_numCharsAllocated = 16}
(gdb) p newData
$11 = (AsciiString::AsciiStringData *) 0x7ffff6e92370
(gdb) p newData->peek()
$12 = 0x7ffff6e92374 ""
@zachreizner
Copy link
Author

m_debugptr is initially 0x7ffff6e92374 and then suddenly becomes 0x7f00f6e92374 after newData->peek()[0] = 0;.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment