diff --git a/cfg/windows.cfg b/cfg/windows.cfg
index 55f91676d..7cffeb7d9 100644
--- a/cfg/windows.cfg
+++ b/cfg/windows.cfg
@@ -1001,7 +1001,7 @@
HeapAlloc
HeapReAlloc
- HeapFree
+ HeapFree
IoAllocateErrorLogEntry
@@ -1062,7 +1062,7 @@
VirtualAllocEx
VirtualAllocExNuma
- VirtualFreeEx
+ VirtualFreeEx
LocalAlloc
diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp
index 3f1e48fb4..f167afa5d 100644
--- a/lib/checkleakautovar.cpp
+++ b/lib/checkleakautovar.cpp
@@ -207,7 +207,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (tok->str() == "(" && tok->previous()->isName()) {
VarInfo::AllocInfo allocation(0, VarInfo::NOALLOC);
- functionCall(tok->previous(), varInfo, allocation);
+ functionCall(tok->previous(), varInfo, allocation, nullptr);
tok = tok->link();
continue;
}
@@ -274,9 +274,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// allocation?
if (varTok->next()->astOperand2() && Token::Match(varTok->next()->astOperand2()->previous(), "%type% (")) {
- int i = _settings->library.alloc(varTok->next()->astOperand2()->previous());
- if (i > 0) {
- alloctype[varTok->varId()].type = i;
+ const Library::AllocFunc* f = _settings->library.alloc(varTok->next()->astOperand2()->previous());
+ if (f && f->arg == -1) {
+ alloctype[varTok->varId()].type = f->groupId;
alloctype[varTok->varId()].status = VarInfo::ALLOC;
}
} else if (_tokenizer->isCPP() && varTok->strAt(2) == "new") {
@@ -301,10 +301,8 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (innerTok->str() == ")")
break;
if (innerTok->str() == "(" && innerTok->previous()->isName()) {
- VarInfo::AllocInfo allocation(_settings->library.dealloc(tok), VarInfo::DEALLOC);
- if (allocation.type == 0)
- allocation.status = VarInfo::NOALLOC;
- functionCall(innerTok->previous(), varInfo, allocation);
+ VarInfo::AllocInfo allocation(0, VarInfo::NOALLOC);
+ functionCall(innerTok->previous(), varInfo, allocation, nullptr);
innerTok = innerTok->link();
}
}
@@ -440,10 +438,11 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// Function call..
else if (Token::Match(tok, "%type% (")) {
- VarInfo::AllocInfo allocation(_settings->library.dealloc(tok), VarInfo::DEALLOC);
+ const Library::AllocFunc* af = _settings->library.dealloc(tok);
+ VarInfo::AllocInfo allocation(af ? af->groupId : 0, VarInfo::DEALLOC);
if (allocation.type == 0)
allocation.status = VarInfo::NOALLOC;
- functionCall(tok, varInfo, allocation);
+ functionCall(tok, varInfo, allocation, af);
tok = tok->next()->link();
@@ -516,13 +515,14 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo *varInfo, const VarInfo::AllocI
}
}
-void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation)
+void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
{
// Ignore function call?
const bool ignore = bool(_settings->library.leakignore.find(tok->str()) != _settings->library.leakignore.end());
if (ignore)
return;
+ int argNr = 1;
for (const Token *arg = tok->tokAt(2); arg; arg = arg->nextArgument()) {
if (_tokenizer->isCPP() && arg->str() == "new") {
arg = arg->next();
@@ -537,10 +537,12 @@ void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const Va
arg = arg->next();
// Is variable allocated?
- changeAllocStatus(varInfo, allocation, tok, arg);
+ if (!af || af->arg == argNr)
+ changeAllocStatus(varInfo, allocation, tok, arg);
} else if (Token::Match(arg, "%name% (")) {
- functionCall(arg, varInfo, allocation);
+ functionCall(arg, varInfo, allocation, af);
}
+ argNr++;
}
}
diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h
index 99779ef05..84edb54a0 100644
--- a/lib/checkleakautovar.h
+++ b/lib/checkleakautovar.h
@@ -105,7 +105,7 @@ private:
std::set notzero);
/** parse function call */
- void functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation);
+ void functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af);
/** parse changes in allocation status */
void changeAllocStatus(VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Token* tok, const Token* arg);
diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp
index 84ea57414..8c36cde81 100644
--- a/lib/checkmemoryleak.cpp
+++ b/lib/checkmemoryleak.cpp
@@ -154,11 +154,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
}
// Does tok2 point on a Library allocation function?
- const int alloctype = settings1->library.alloc(tok2);
+ const int alloctype = settings1->library.alloc(tok2, -1);
if (alloctype > 0) {
- if (alloctype == settings1->library.dealloc("free"))
+ if (alloctype == settings1->library.deallocId("free"))
return Malloc;
- if (alloctype == settings1->library.dealloc("fclose"))
+ if (alloctype == settings1->library.deallocId("fclose"))
return File;
return Library::ismemory(alloctype) ? OtherMem : OtherRes;
}
@@ -227,30 +227,34 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
if (Token::simpleMatch(tok, "fcloseall ( )"))
return File;
- const Token* vartok = tok->tokAt(2);
- while (Token::Match(vartok, "%name% .|::"))
- vartok = vartok->tokAt(2);
+ int argNr = 1;
+ for (const Token* tok2 = tok->tokAt(2); tok2; tok2 = tok2->nextArgument()) {
+ const Token* vartok = tok2;
+ while (Token::Match(vartok, "%name% .|::"))
+ vartok = vartok->tokAt(2);
- if (Token::Match(vartok, "%varid% )|,|-", varid)) {
- if (tok->str() == "realloc" && Token::simpleMatch(vartok->next(), ", 0 )"))
- return Malloc;
-
- if (settings1->standards.posix) {
- if (tok->str() == "close")
- return Fd;
- if (tok->str() == "pclose")
- return Pipe;
- }
-
- // Does tok point on a Library deallocation function?
- const int dealloctype = settings1->library.dealloc(tok);
- if (dealloctype > 0) {
- if (dealloctype == settings1->library.dealloc("free"))
+ if (Token::Match(vartok, "%varid% )|,|-", varid)) {
+ if (tok->str() == "realloc" && Token::simpleMatch(vartok->next(), ", 0 )"))
return Malloc;
- if (dealloctype == settings1->library.dealloc("fclose"))
- return File;
- return Library::ismemory(dealloctype) ? OtherMem : OtherRes;
+
+ if (settings1->standards.posix) {
+ if (tok->str() == "close")
+ return Fd;
+ if (tok->str() == "pclose")
+ return Pipe;
+ }
+
+ // Does tok point on a Library deallocation function?
+ const int dealloctype = settings1->library.dealloc(tok, argNr);
+ if (dealloctype > 0) {
+ if (dealloctype == settings1->library.deallocId("free"))
+ return Malloc;
+ if (dealloctype == settings1->library.deallocId("fclose"))
+ return File;
+ return Library::ismemory(dealloctype) ? OtherMem : OtherRes;
+ }
}
+ argNr++;
}
}
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index b4d990fd0..97bb9b3f4 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -1137,7 +1137,7 @@ void CheckStl::checkAutoPointer()
std::set autoPtrVarId;
std::map mallocVarId; // variables allocated by the malloc-like function
const char STL_CONTAINER_LIST[] = "array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|vector|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset|basic_string";
- const int malloc = _settings->library.alloc("malloc"); // allocation function, which are not compatible with auto_ptr
+ const int malloc = _settings->library.allocId("malloc"); // allocation function, which are not compatible with auto_ptr
const bool printStyle = _settings->isEnabled("style");
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
@@ -1153,7 +1153,7 @@ void CheckStl::checkAutoPointer()
if (Token::Match(tok3, "( new %type%") && hasArrayEndParen(tok3)) {
autoPointerArrayError(tok2->next());
}
- if (Token::Match(tok3, "( %name% (") && malloc && _settings->library.alloc(tok3->next()) == malloc) {
+ if (Token::Match(tok3, "( %name% (") && malloc && _settings->library.alloc(tok3->next(), -1) == malloc) {
// malloc-like function allocated memory passed to the auto_ptr constructor -> error
autoPointerMallocError(tok2->next(), tok3->next()->str());
}
@@ -1197,7 +1197,7 @@ void CheckStl::checkAutoPointer()
if (iter != autoPtrVarId.end()) {
autoPointerArrayError(tok);
}
- } else if (Token::Match(tok, "%var% = %name% (") && malloc && _settings->library.alloc(tok->tokAt(2)) == malloc) {
+ } else if (Token::Match(tok, "%var% = %name% (") && malloc && _settings->library.alloc(tok->tokAt(2), -1) == malloc) {
// C library function like 'malloc' used together with auto pointer -> error
std::set::const_iterator iter = autoPtrVarId.find(tok->varId());
if (iter != autoPtrVarId.end()) {
@@ -1206,7 +1206,7 @@ void CheckStl::checkAutoPointer()
// it is not an auto pointer variable and it is allocated by malloc like function.
mallocVarId.insert(std::make_pair(tok->varId(), tok->strAt(2)));
}
- } else if (Token::Match(tok, "%var% . reset ( %name% (") && malloc && _settings->library.alloc(tok->tokAt(4)) == malloc) {
+ } else if (Token::Match(tok, "%var% . reset ( %name% (") && malloc && _settings->library.alloc(tok->tokAt(4), -1) == malloc) {
// C library function like 'malloc' used when resetting auto pointer -> error
std::set::const_iterator iter = autoPtrVarId.find(tok->varId());
if (iter != autoPtrVarId.end()) {
diff --git a/lib/library.cpp b/lib/library.cpp
index 78c38539b..22afb8bfe 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -139,9 +139,9 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
int allocationId = 0;
for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
if (strcmp(memorynode->Name(),"dealloc")==0) {
- const std::map::const_iterator it = _dealloc.find(memorynode->GetText());
+ const std::map::const_iterator it = _dealloc.find(memorynode->GetText());
if (it != _dealloc.end()) {
- allocationId = it->second;
+ allocationId = it->second.groupId;
break;
}
}
@@ -158,14 +158,29 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
for (const tinyxml2::XMLElement *memorynode = node->FirstChildElement(); memorynode; memorynode = memorynode->NextSiblingElement()) {
const std::string memorynodename = memorynode->Name();
if (memorynodename == "alloc") {
- _alloc[memorynode->GetText()] = allocationId;
+ AllocFunc temp;
+ temp.groupId = allocationId;
+
const char *init = memorynode->Attribute("init");
if (init && strcmp(init,"false")==0) {
returnuninitdata.insert(memorynode->GetText());
}
- } else if (memorynodename == "dealloc")
- _dealloc[memorynode->GetText()] = allocationId;
- else if (memorynodename == "use")
+ const char *arg = memorynode->Attribute("arg");
+ if (arg)
+ temp.arg = atoi(arg);
+ else
+ temp.arg = -1;
+ _alloc[memorynode->GetText()] = temp;
+ } else if (memorynodename == "dealloc") {
+ AllocFunc temp;
+ temp.groupId = allocationId;
+ const char *arg = memorynode->Attribute("arg");
+ if (arg)
+ temp.arg = atoi(arg);
+ else
+ temp.arg = 1;
+ _dealloc[memorynode->GetText()] = temp;
+ } else if (memorynodename == "use")
use.insert(memorynode->GetText());
else
unknown_elements.insert(memorynodename);
@@ -772,18 +787,32 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
}
-/** get allocation id for function */
-int Library::alloc(const Token *tok) const
+/** get allocation info for function */
+const Library::AllocFunc* Library::alloc(const Token *tok) const
{
const std::string funcname = functionName(tok);
- return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getid(_alloc, funcname);
+ return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_alloc, funcname);
+}
+
+/** get deallocation info for function */
+const Library::AllocFunc* Library::dealloc(const Token *tok) const
+{
+ const std::string funcname = functionName(tok);
+ return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_dealloc, funcname);
+}
+
+/** get allocation id for function */
+int Library::alloc(const Token *tok, int arg) const
+{
+ const Library::AllocFunc* af = alloc(tok);
+ return (af && af->arg == arg) ? af->groupId : 0;
}
/** get deallocation id for function */
-int Library::dealloc(const Token *tok) const
+int Library::dealloc(const Token *tok, int arg) const
{
- const std::string funcname = functionName(tok);
- return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getid(_dealloc, funcname);
+ const Library::AllocFunc* af = dealloc(tok);
+ return (af && af->arg == arg) ? af->groupId : 0;
}
diff --git a/lib/library.h b/lib/library.h
index b47a8d46d..3fb8a7ddf 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -64,29 +64,54 @@ public:
/** this is primarily meant for unit tests. it only returns true/false */
bool loadxmldata(const char xmldata[], std::size_t len);
- /** get allocation id for function by name (deprecated, use other alloc) */
- int alloc(const char name[]) const {
- return getid(_alloc, name);
- }
+ struct AllocFunc {
+ int groupId;
+ int arg;
+ };
+
+ /** get allocation info for function */
+ const AllocFunc* alloc(const Token *tok) const;
+
+ /** get deallocation info for function */
+ const AllocFunc* dealloc(const Token *tok) const;
/** get allocation id for function */
- int alloc(const Token *tok) const;
+ int alloc(const Token *tok, int arg) const;
/** get deallocation id for function */
- int dealloc(const Token *tok) const;
+ int dealloc(const Token *tok, int arg) const;
+
+ /** get allocation info for function by name (deprecated, use other alloc) */
+ const AllocFunc* alloc(const char name[]) const {
+ return getAllocDealloc(_alloc, name);
+ }
+
+ /** get deallocation info for function by name (deprecated, use other alloc) */
+ const AllocFunc* dealloc(const char name[]) const {
+ return getAllocDealloc(_dealloc, name);
+ }
+
+ /** get allocation id for function by name (deprecated, use other alloc) */
+ int allocId(const char name[]) const {
+ const AllocFunc* af = getAllocDealloc(_alloc, name);
+ return af ? af->groupId : 0;
+ }
/** get deallocation id for function by name (deprecated, use other alloc) */
- int dealloc(const char name[]) const {
- return getid(_dealloc, name);
+ int deallocId(const char name[]) const {
+ const AllocFunc* af = getAllocDealloc(_dealloc, name);
+ return af ? af->groupId : 0;
}
/** set allocation id for function */
- void setalloc(const std::string &functionname, int id) {
- _alloc[functionname] = id;
+ void setalloc(const std::string &functionname, int id, int arg) {
+ _alloc[functionname].groupId = id;
+ _alloc[functionname].arg = arg;
}
- void setdealloc(const std::string &functionname, int id) {
- _dealloc[functionname] = id;
+ void setdealloc(const std::string &functionname, int id, int arg) {
+ _dealloc[functionname].groupId = id;
+ _dealloc[functionname].arg = arg;
}
/** add noreturn function setting */
@@ -98,11 +123,17 @@ public:
static bool ismemory(int id) {
return ((id > 0) && ((id & 1) == 0));
}
+ static bool ismemory(const AllocFunc* func) {
+ return ((func->groupId > 0) && ((func->groupId & 1) == 0));
+ }
/** is allocation type resource? */
static bool isresource(int id) {
return ((id > 0) && ((id & 1) == 1));
}
+ static bool isresource(const AllocFunc* func) {
+ return ((func->groupId > 0) && ((func->groupId & 1) == 1));
+ }
bool formatstr_function(const std::string& funcname) const {
return _formatstr.find(funcname) != _formatstr.cend();
@@ -443,8 +474,8 @@ private:
int allocid;
std::set _files;
std::set _useretval;
- std::map _alloc; // allocation functions
- std::map _dealloc; // deallocation functions
+ std::map _alloc; // allocation functions
+ std::map _dealloc; // deallocation functions
std::map _noreturn; // is function noreturn?
std::set _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
std::map _reporterrors;
@@ -462,9 +493,9 @@ private:
const ArgumentChecks * getarg(const Token *ftok, int argnr) const;
- static int getid(const std::map &data, const std::string &name) {
- const std::map::const_iterator it = data.find(name);
- return (it == data.end()) ? 0 : it->second;
+ static const AllocFunc* getAllocDealloc(const std::map &data, const std::string &name) {
+ const std::map::const_iterator it = data.find(name);
+ return (it == data.end()) ? nullptr : &it->second;
}
};
diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp
index 6e2ccabaf..b81beebca 100644
--- a/test/testleakautovar.cpp
+++ b/test/testleakautovar.cpp
@@ -32,11 +32,11 @@ private:
void run() {
int id = 0;
while (!settings.library.ismemory(++id));
- settings.library.setalloc("malloc", id);
- settings.library.setdealloc("free", id);
+ settings.library.setalloc("malloc", id, -1);
+ settings.library.setdealloc("free", id, 1);
while (!settings.library.isresource(++id));
- settings.library.setalloc("fopen", id);
- settings.library.setdealloc("fclose", id);
+ settings.library.setalloc("fopen", id, -1);
+ settings.library.setdealloc("fclose", id, 1);
// Assign
TEST_CASE(assign1);
@@ -1269,8 +1269,7 @@ private:
" HeapFree(MyHeap, 0, b);"
" HeapDestroy(MyHeap);"
"}");
- TODO_ASSERT_EQUALS("", "[test.c:1]: (error) Mismatching allocation and deallocation: MyHeap\n"
- "[test.c:1]: (error) Resource handle 'MyHeap' freed twice.\n", errout.str());
+ ASSERT_EQUALS("", errout.str());
check("void f() {"
" int *a = HeapAlloc(GetProcessHeap(), 0, sizeof(int));"
@@ -1287,8 +1286,7 @@ private:
" HeapFree(MyHeap, 0, a);"
" HeapDestroy(MyHeap);"
"}");
- TODO_ASSERT_EQUALS("[test.c:1] (error) Memory leak: b", "[test.c:1]: (error) Mismatching allocation and deallocation: MyHeap\n"
- "[test.c:1]: (error) Memory leak: b\n", errout.str());
+ ASSERT_EQUALS("[test.c:1]: (error) Memory leak: b\n", errout.str());
check("void f() {"
" HANDLE MyHeap = HeapCreate(0, 0, 0);"
@@ -1297,7 +1295,8 @@ private:
" HeapFree(MyHeap, 0, a);"
" HeapFree(MyHeap, 0, b);"
"}");
- TODO_ASSERT_EQUALS("[test.c:1] (error) Resource leak: MyHeap", "[test.c:1]: (error) Mismatching allocation and deallocation: MyHeap\n", errout.str());
+ TODO_ASSERT_EQUALS("[test.c:1] (error) Resource leak: MyHeap",
+ "", errout.str());
check("void f() {"
" HANDLE MyHeap = HeapCreate(0, 0, 0);"
@@ -1305,8 +1304,9 @@ private:
" int *b = HeapAlloc(MyHeap, 0, sizeof(int));"
" HeapFree(MyHeap, 0, a);"
"}");
- TODO_ASSERT_EQUALS("[test.c:1] (error) Resource leak: MyHeap\n[test.c:1] (error) Memory leak: b",
- "[test.c:1]: (error) Mismatching allocation and deallocation: MyHeap\n[test.c:1]: (error) Memory leak: b\n", errout.str());
+ TODO_ASSERT_EQUALS("[test.c:1] (error) Memory leak: MyHeap\n"
+ "[test.c:1] (error) Memory leak: b",
+ "[test.c:1]: (error) Memory leak: b\n", errout.str());
}
};
diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp
index 45e2beae3..0cf74ceff 100644
--- a/test/testlibrary.cpp
+++ b/test/testlibrary.cpp
@@ -43,6 +43,7 @@ private:
TEST_CASE(function_warn);
TEST_CASE(memory);
TEST_CASE(memory2); // define extra "free" allocation functions
+ TEST_CASE(memory3);
TEST_CASE(resource);
TEST_CASE(podtype);
TEST_CASE(container);
@@ -358,7 +359,11 @@ private:
ASSERT(library.argumentChecks.empty());
ASSERT(Library::ismemory(library.alloc("CreateX")));
- ASSERT_EQUALS(library.alloc("CreateX"), library.dealloc("DeleteX"));
+ ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
+ const Library::AllocFunc* af = library.alloc("CreateX");
+ ASSERT(af && af->arg == -1);
+ const Library::AllocFunc* df = library.dealloc("DeleteX");
+ ASSERT(df && df->arg == 1);
}
void memory2() const {
const char xmldata1[] = "\n"
@@ -380,8 +385,30 @@ private:
library.loadxmldata(xmldata1, sizeof(xmldata1));
library.loadxmldata(xmldata2, sizeof(xmldata2));
- ASSERT_EQUALS(library.dealloc("free"), library.alloc("malloc"));
- ASSERT_EQUALS(library.dealloc("free"), library.alloc("foo"));
+ ASSERT_EQUALS(library.deallocId("free"), library.allocId("malloc"));
+ ASSERT_EQUALS(library.deallocId("free"), library.allocId("foo"));
+ }
+ void memory3() const {
+ const char xmldata[] = "\n"
+ "\n"
+ " \n"
+ " CreateX\n"
+ " DeleteX\n"
+ " \n"
+ "";
+
+ Library library;
+ readLibrary(library, xmldata);
+ ASSERT(library.use.empty());
+ ASSERT(library.leakignore.empty());
+ ASSERT(library.argumentChecks.empty());
+
+ const Library::AllocFunc* af = library.alloc("CreateX");
+ ASSERT(af && af->arg == 5);
+ const Library::AllocFunc* df = library.dealloc("DeleteX");
+ ASSERT(df && df->arg == 2);
+
+ ASSERT(library.returnuninitdata.find("CreateX") != library.returnuninitdata.cend());
}
void resource() const {
@@ -399,8 +426,8 @@ private:
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
- ASSERT(Library::isresource(library.alloc("CreateX")));
- ASSERT_EQUALS(library.alloc("CreateX"), library.dealloc("DeleteX"));
+ ASSERT(Library::isresource(library.allocId("CreateX")));
+ ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
}
void podtype() const {