Fix memory corruption problem in the preprocessor, removing custom hash-tables/etc. and replacing with std containers.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23623 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-20 18:18:36 +00:00
parent ab3080353a
commit 1f4104fbb1
7 changed files with 172 additions and 957 deletions

View file

@ -98,10 +98,6 @@ namespace {
using namespace glslang;
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// String table: //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
const struct {
int val;
const char *str;
@ -129,579 +125,71 @@ const struct {
{ CPP_INC_OP, "++" },
};
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// String table: //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
#define INIT_STRING_TABLE_SIZE 16384
/*
* InitStringTable() - Initialize the string table.
*
*/
int InitStringTable(TPpContext::StringTable *stable)
{
stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE);
if (!stable->strings)
return 0;
// Zero-th offset means "empty" so don't use it.
stable->nextFree = 1;
stable->size = INIT_STRING_TABLE_SIZE;
return 1;
} // InitStringTable
/*
* FreeStringTable() - Free the string table.
*
*/
void FreeStringTable(TPpContext::StringTable *stable)
{
if (stable->strings)
free(stable->strings);
stable->strings = NULL;
stable->nextFree = 0;
stable->size = 0;
} // FreeStringTable
/*
* HashString() - Hash a string with the base hash function.
*
*/
int HashString(const char *s)
{
int hval = 0;
while (*s) {
hval = (hval*13507 + *s*197) ^ (hval >> 2);
s++;
}
return hval & 0x7fffffff;
} // HashString
/*
* HashString2() - Hash a string with the incrimenting hash function.
*
*/
int HashString2(const char *s)
{
int hval = 0;
while (*s) {
hval = (hval*729 + *s*37) ^ (hval >> 1);
s++;
}
return hval;
} // HashString2
/*
* AddString() - Add a string to a string table. Return it's offset.
*
*/
int AddString(TPpContext::StringTable *stable, const char *s)
{
int len, loc;
char *str;
len = (int) strlen(s);
if (stable->nextFree + len + 1 >= stable->size) {
assert(stable->size < 1000000);
str = (char *) malloc(stable->size*2);
memcpy(str, stable->strings, stable->size);
free(stable->strings);
stable->strings = str;
}
loc = stable->nextFree;
strcpy(&stable->strings[loc], s);
stable->nextFree += len + 1;
return loc;
} // AddString
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////// Hash table: ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
#define INIT_HASH_TABLE_SIZE 2047
/*
* InitHashTable() - Initialize the hash table.
*
*/
int InitHashTable(TPpContext::HashTable *htable, int fsize)
{
int ii;
htable->entry = (TPpContext::HashEntry *) malloc(sizeof(TPpContext::HashEntry)*fsize);
if (! htable->entry)
return 0;
htable->size = fsize;
for (ii = 0; ii < fsize; ii++) {
htable->entry[ii].index = 0;
htable->entry[ii].value = 0;
}
htable->entries = 0;
for (ii = 0; ii <= TPpContext::hashTableMaxCollisions; ii++)
htable->counts[ii] = 0;
return 1;
} // InitHashTable
/*
* FreeHashTable() - Free the hash table.
*
*/
void FreeHashTable(TPpContext::HashTable *htable)
{
if (htable->entry)
free(htable->entry);
htable->entry = NULL;
htable->size = 0;
htable->entries = 0;
} // FreeHashTable
/*
* Empty() - See if a hash table entry is empty.
*
*/
int Empty(TPpContext::HashTable *htable, int hashloc)
{
assert(hashloc >= 0 && hashloc < htable->size);
if (htable->entry[hashloc].index == 0) {
return 1;
} else {
return 0;
}
} // Empty
/*
* Match() - See if a hash table entry is matches a string.
*
*/
int Match(TPpContext::HashTable *htable, TPpContext::StringTable *stable, const char *s, int hashloc)
{
int strloc;
strloc = htable->entry[hashloc].index;
if (!strcmp(s, &stable->strings[strloc])) {
return 1;
} else {
return 0;
}
} // Match
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////// Atom table: ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
#define INIT_ATOM_TABLE_SIZE 1024
/*
* GrowAtomTable() - Grow the atom table to at least "size" if it's smaller.
*
*/
int GrowAtomTable(TPpContext::AtomTable *atable, int size)
{
int *newmap, *newrev;
if (atable->size < size) {
if (atable->amap) {
newmap = (int*)realloc(atable->amap, sizeof(int)*size);
newrev = (int*)realloc(atable->arev, sizeof(int)*size);
} else {
newmap = (int*)malloc(sizeof(int)*size);
newrev = (int*)malloc(sizeof(int)*size);
atable->size = 0;
}
if (!newmap || !newrev) {
/* failed to grow -- error */
if (newmap)
atable->amap = newmap;
if (newrev)
atable->amap = newrev;
return -1;
}
memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
atable->amap = newmap;
atable->arev = newrev;
atable->size = size;
}
return 0;
} // GrowAtomTable
/*
* lReverse() - Reverse the bottom 20 bits of a 32 bit int.
*
*/
int lReverse(int fval)
{
unsigned int in = fval;
int result = 0, cnt = 0;
while(in) {
result <<= 1;
result |= in&1;
in >>= 1;
cnt++;
}
// Don't use all 31 bits. One million atoms is plenty and sometimes the
// upper bits are used for other things.
if (cnt < 20)
result <<= 20 - cnt;
return result;
} // lReverse
/*
* AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1.
*
*/
int AllocateAtom(TPpContext::AtomTable *atable)
{
if (atable->nextFree >= atable->size)
GrowAtomTable(atable, atable->nextFree*2);
atable->amap[atable->nextFree] = -1;
atable->arev[atable->nextFree] = lReverse(atable->nextFree);
atable->nextFree++;
return atable->nextFree - 1;
} // AllocateAtom
/*
* SetAtomValue() - Allocate a new atom associated with "hashindex".
*
*/
void SetAtomValue(TPpContext::AtomTable *atable, int atomnumber, int hashindex)
{
atable->amap[atomnumber] = atable->htable.entry[hashindex].index;
atable->htable.entry[hashindex].value = atomnumber;
} // SetAtomValue
/*
* FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full.
*
*/
int FindHashLoc(TPpContext::AtomTable *atable, const char *s)
{
int hashloc, hashdelta, count;
int FoundEmptySlot = 0;
#ifdef DUMP_TABLE
int collision[TPpContext::hashTableMaxCollisions + 1];
#endif
hashloc = HashString(s) % atable->htable.size;
if (!Empty(&atable->htable, hashloc)) {
if (Match(&atable->htable, &atable->stable, s, hashloc))
return hashloc;
#ifdef DUMP_TABLE
collision[0] = hashloc;
#endif
hashdelta = HashString2(s);
count = 0;
while (count < TPpContext::hashTableMaxCollisions) {
hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size;
if (!Empty(&atable->htable, hashloc)) {
if (Match(&atable->htable, &atable->stable, s, hashloc)) {
return hashloc;
}
} else {
FoundEmptySlot = 1;
break;
}
count++;
#ifdef DUMP_TABLE
collision[count] = hashloc;
#endif
}
if (! FoundEmptySlot) {
#ifdef DUMP_TABLE
{
int ii;
char str[200];
printf(str, "*** Hash failed with more than %d collisions. Must increase hash table size. ***",
hashTableMaxCollisions);
printf(str, "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta);
for (ii = 0; ii <= hashTableMaxCollisions; ii++) {
printf(str, "*** Collides on try %d at hash entry %04x with \"%s\"",
ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value));
}
}
#endif
return -1;
} else {
atable->htable.counts[count]++;
}
}
return hashloc;
} // FindHashLoc
} // end anonymous namespace
namespace glslang {
/*
* IncreaseHashTableSize()
*
*/
int TPpContext::IncreaseHashTableSize(AtomTable *atable)
//
// Map a new or existing string to an atom, inventing a new atom if necessary.
//
int TPpContext::LookUpAddString(const char *s)
{
int ii, strloc, oldhashloc, value, size;
AtomTable oldtable;
char *s;
// Save the old atom table and create a new one:
oldtable = *atable;
size = oldtable.htable.size*2 + 1;
if (! InitAtomTable(atable, size))
return 0;
// Add all the existing values to the new atom table preserving their atom values:
for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) {
strloc = oldtable.amap[ii];
s = &oldtable.stable.strings[strloc];
oldhashloc = FindHashLoc(&oldtable, s);
assert(oldhashloc >= 0);
value = oldtable.htable.entry[oldhashloc].value;
AddAtomFixed(atable, s, value);
}
FreeAtomTable(&oldtable);
return 1;
} // IncreaseHashTableSize
/*
* LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and
* initialize the atom value in the hash table to 0. Return the hash table index.
*/
int TPpContext::LookUpAddStringHash(AtomTable *atable, const char *s)
{
int hashloc, strloc;
while(1) {
hashloc = FindHashLoc(atable, s);
if (hashloc >= 0)
break;
IncreaseHashTableSize(atable);
}
if (Empty(&atable->htable, hashloc)) {
atable->htable.entries++;
strloc = AddString(&atable->stable, s);
atable->htable.entry[hashloc].index = strloc;
atable->htable.entry[hashloc].value = 0;
}
return hashloc;
} // LookUpAddStringHash
/*
* LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and
* initialize the atom value in the hash table to the next atom number.
* Return the atom value of string.
*/
int TPpContext::LookUpAddString(AtomTable *atable, const char *s)
{
int hashindex, atom;
hashindex = LookUpAddStringHash(atable, s);
atom = atable->htable.entry[hashindex].value;
if (atom == 0) {
atom = AllocateAtom(atable);
SetAtomValue(atable, atom, hashindex);
}
return atom;
} // LookUpAddString
/*
* GetAtomString()
*
*/
const char *TPpContext::GetAtomString(AtomTable *atable, int atom)
{
int soffset;
if (atom > 0 && atom < atable->nextFree) {
soffset = atable->amap[atom];
if (soffset > 0 && soffset < atable->stable.nextFree) {
return &atable->stable.strings[soffset];
} else {
return "<internal error: bad soffset>";
}
} else {
if (atom == 0) {
return "<null atom>";
} else {
if (atom == EOF) {
return "<EOF>";
} else {
return "<invalid atom>";
}
}
}
} // GetAtomString
/*
* GetReversedAtom()
*
*/
int TPpContext::GetReversedAtom(TPpContext::AtomTable *atable, int atom)
{
if (atom > 0 && atom < atable->nextFree)
return atable->arev[atom];
TAtomMap::const_iterator it = atomMap.find(s);
if (it == atomMap.end())
return AddAtomFixed(s, nextAtom++);
else
return 0;
} // GetReversedAtom
return it->second;
}
/*
* AddAtom() - Add a string to the atom, hash and string tables if it isn't already there.
* Return it's atom index.
*/
int TPpContext::AddAtom(TPpContext::AtomTable *atable, const char *s)
//
// Map an already created atom to its string.
//
const char *TPpContext::GetAtomString(int atom)
{
int atom = LookUpAddString(atable, s);
if (atom == 0)
return "<null atom>";
if (atom < 0)
return "<EOF>";
if ((size_t)atom < stringMap.size())
return stringMap[atom]->c_str();
return "<invalid atom>";
}
//
// Add forced mapping of string to atom.
//
int TPpContext::AddAtomFixed(const char *s, int atom)
{
TAtomMap::const_iterator it = atomMap.insert(std::pair<TString, int>(s, atom)).first;
if (stringMap.size() < (size_t)atom + 1)
stringMap.resize(atom + 100);
stringMap[atom] = &it->first;
return atom;
} // AddAtom
}
/*
* AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there.
* Assign it the atom value of "atom".
*/
int TPpContext::AddAtomFixed(AtomTable *atable, const char *s, int atom)
//
// Initialize the atom table.
//
void TPpContext::InitAtomTable()
{
int hashindex, lsize;
hashindex = LookUpAddStringHash(atable, s);
if (atable->nextFree >= atable->size || atom >= atable->size) {
lsize = atable->size*2;
if (lsize <= atom)
lsize = atom + 1;
GrowAtomTable(atable, lsize);
}
atable->amap[atom] = atable->htable.entry[hashindex].index;
atable->htable.entry[hashindex].value = atom;
//if (atom >= atable->nextFree)
// atable->nextFree = atom + 1;
while (atom >= atable->nextFree) {
atable->arev[atable->nextFree] = lReverse(atable->nextFree);
atable->nextFree++;
}
return atom;
} // AddAtomFixed
/*
* InitAtomTable() - Initialize the atom table.
*
*/
int TPpContext::InitAtomTable(AtomTable *atable, int htsize)
{
int ii;
htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize;
if (! InitStringTable(&atable->stable))
return 0;
if (! InitHashTable(&atable->htable, htsize))
return 0;
atable->nextFree = 0;
atable->amap = NULL;
atable->size = 0;
atable->arev = 0;
GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE);
if (!atable->amap)
return 0;
// Initialize lower part of atom table to "<undefined>" atom:
AddAtomFixed(atable, "<undefined>", 0);
for (ii = 0; ii < CPP_FIRST_USER_TOKEN_SY; ii++)
atable->amap[ii] = atable->amap[0];
// Add single character tokens to the atom table:
const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#";
char t[2];
{
const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#";
char t[2];
t[1] = '\0';
while (*s) {
t[0] = *s;
AddAtomFixed(atable, t, s[0]);
s++;
}
t[1] = '\0';
while (*s) {
t[0] = *s;
AddAtomFixed(t, s[0]);
s++;
}
// Add multiple character scanner tokens :
for (int ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
AddAtomFixed(tokens[ii].str, tokens[ii].val);
for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
AddAtomFixed(atable, tokens[ii].str, tokens[ii].val);
AddAtom(atable, "<*** end fixed atoms ***>");
return 1;
} // InitAtomTable
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Debug Printing Functions: //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/*
* PrintAtomTable()
*
*/
void TPpContext::PrintAtomTable(AtomTable *atable)
{
int ii;
char str[200];
for (ii = 0; ii < atable->nextFree; ii++) {
printf(str, "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]);
}
printf(str, "Hash table: size=%d, entries=%d, collisions=",
atable->htable.size, atable->htable.entries);
for (ii = 0; ii < hashTableMaxCollisions; ii++) {
printf(str, " %d", atable->htable.counts[ii]);
}
} // PrintAtomTable
/*
* GetStringOfAtom()
*
*/
char* TPpContext::GetStringOfAtom(AtomTable *atable, int atom)
{
char* chr_str;
chr_str=&atable->stable.strings[atable->amap[atom]];
return chr_str;
} // GetStringOfAtom
/*
* FreeAtomTable() - Free the atom table and associated memory
*
*/
void TPpContext::FreeAtomTable(AtomTable *atable)
{
FreeStringTable(&atable->stable);
FreeHashTable(&atable->htable);
if (atable->amap)
free(atable->amap);
if (atable->arev)
free(atable->arev);
atable->amap = NULL;
atable->arev = NULL;
atable->nextFree = 0;
atable->size = 0;
} // FreeAtomTable
nextAtom = CPP_FIRST_USER_TOKEN_SY;
}
} // end namespace glslang