Этот код не делает то, что вы думаете:
Result CreateServer(Server thisServer)
{
if (thisServer = (Server)malloc(sizeof(struct Server_t)))
{
thisServer->UsersList = CreateLinkedList();
return Success;
}
return Failed;
}
Если вы собираетесь вернуть Server
по значению, вы должны передать указатель в функцию:
Result CreateServer(Server *thisServer)
{
if (*thisServer = (Server)malloc(sizeof(struct Server_t)))
{
(*thisServer)->UsersList = CreateLinkedList();
return Success;
}
return Failed;
}
Исходный код утечки памяти и вызывает ошибки сегментации, потому что значение struct Server_t
, используемое после CreateServer()
, не было инициализировано.
Рабочий код
следующий код работает под valgrind
(память, выделенная системой, все еще доступна, но ничего не просочилось или не использовалось).Проблема действительно была в функции CreateServer()
, как было диагностировано ранее.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
typedef int Element;
typedef struct Node *Node;
struct Node
{
Node m_prev;
Node m_next;
Element m_data;
};
struct LinkedList
{
Node m_head;
Node m_tail;
int m_numOfElements;
};
typedef struct LinkedList *List;
struct Server_t
{
List UsersList;
};
typedef struct Server_t *Server;
typedef enum Result { Failed, Success } Result;
extern Result CreateServer(Server *thisServer);
extern Result AddNode(List list, Element data);
extern void SetPrev(Node node, Node toSet);
extern void SetNext(Node node, Node toSet);
extern Node CreateNewNode(Element data);
extern List CreateLinkedList(void);
extern void DestroyServer(Server server);
extern void DestroyLinkedList(List list);
List CreateLinkedList(void)
{
List list = (List)malloc(sizeof(struct LinkedList));
if (list == NULL)
{
printf("memory alloc failed\n");
return NULL;
}
list->m_head = NULL;
list->m_tail = NULL;
list->m_numOfElements = 0;
return list;
}
Node CreateNewNode(Element data)
{
Node newNode = (Node)malloc(sizeof(struct Node));
newNode->m_next = NULL;
newNode->m_prev = NULL;
newNode->m_data = data;
return newNode;
}
void SetNext(Node node, Node toSet)
{
node->m_next = toSet;
}
void SetPrev(Node node, Node toSet)
{
node->m_prev = toSet;
}
Result AddNode(List list, Element data)
{
Node newNode;
//there is no linked list to add the element to
if (list == NULL)
return Failed;
newNode = CreateNewNode(data);
if (newNode == NULL)
{
printf("Failed allocating memory\n");
return Failed;
}
//Empty Linked List
if (list->m_head == NULL)
{
list->m_tail = list->m_head = newNode;
}
else
{
SetNext(list->m_tail,newNode);
SetPrev(newNode, list->m_tail);
list->m_tail = newNode;
}
//increase num of elements
list->m_numOfElements++;
return Success;
}
Result CreateServer(Server *thisServer)
{
if ((*thisServer = (Server)malloc(sizeof(struct Server_t))) != 0)
{
if (((*thisServer)->UsersList = CreateLinkedList()) != 0)
return Success;
}
return Failed;
}
void DestroyLinkedList(List list)
{
Node node;
Node next;
assert(list != 0);
for (node = list->m_head; node != 0; node = next)
{
next = node->m_next;
free(node);
}
free(list);
}
void DestroyServer(Server server)
{
assert(server != 0);
assert(server->UsersList != 0);
DestroyLinkedList(server->UsersList);
free(server);
}
int main(void)
{
Server mainFacebookServer;
if (CreateServer(&mainFacebookServer) == Success)
{
if (AddNode(mainFacebookServer->UsersList, 1) == Success)
{
/* Use new user list */
}
DestroyServer(mainFacebookServer);
}
return(0);
}
При компиляции с XCode 4.x GCC / LLVM на MacOS X 10.7.2 и запуске с Valgrind 3.7.0, Iget:
$ /usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -Werror xxx.c -o xxx
$ valgrind --leak-check=full xxx
==51464== Memcheck, a memory error detector
==51464== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==51464== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==51464== Command: xxx
==51464==
==51464==
==51464== HEAP SUMMARY:
==51464== in use at exit: 2,095 bytes in 32 blocks
==51464== total heap usage: 35 allocs, 3 frees, 2,151 bytes allocated
==51464==
==51464== LEAK SUMMARY:
==51464== definitely lost: 0 bytes in 0 blocks
==51464== indirectly lost: 0 bytes in 0 blocks
==51464== possibly lost: 0 bytes in 0 blocks
==51464== still reachable: 2,095 bytes in 32 blocks
==51464== suppressed: 0 bytes in 0 blocks
==51464== Reachable blocks (those to which a pointer was found) are not shown.
==51464== To see them, rerun with: --leak-check=full --show-reachable=yes
==51464==
==51464== For counts of detected and suppressed errors, rerun with: -v
==51464== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
$
При запуске с --show-reachable=yes
дополнительные отчеты аналогичны этому (из другого прогона, как вы можете видеть:
==51375== 616 bytes in 7 blocks are still reachable in loss record 8 of 8
==51375== at 0xC3F3: calloc (vg_replace_malloc.c:569)
==51375== by 0x312AAA: _xpc_calloc (in /usr/lib/system/libxpc.dylib)
==51375== by 0x313384: _xpc_base_create (in /usr/lib/system/libxpc.dylib)
==51375== by 0x319CE2: xpc_string_create (in /usr/lib/system/libxpc.dylib)
==51375== by 0x318EF5: xpc_dictionary_set_string (in /usr/lib/system/libxpc.dylib)
==51375== by 0x31AF49: _libxpc_initializer (in /usr/lib/system/libxpc.dylib)
==51375== by 0x18E7D: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==51375== by 0x7FFF5FC0FD19: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==51375== by 0x7FFF5FC0FA65: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==51375== by 0x7FFF5FC0D257: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==51375== by 0x7FFF5FC0D1F0: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==51375== by 0x7FFF5FC0E02A: ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==51375==
Не интересно - кромеза объем выполняемой фоновой работы - и определенно проблема (или нет) с системой, а не с кодом в программе.