Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Changes to W32 pipe/process handling, trying to get it working.

Fixed broken remote testing.
Added dump of allocator tree if allocator OOMs.
  • Loading branch information...
commit 6ad4812d9adf54ce9dec4ce39804e4159afef84c 1 parent 16719cd
Caleb James DeLisle authored
Showing with 363 additions and 187 deletions.
  1. +2 −1  CMakeLists.txt
  2. +2 −2 admin/Admin.c
  3. +1 −1  admin/AdminLog.c
  4. +4 −4 admin/Configurator.c
  5. +1 −1  admin/angel/AngelInit.c
  6. +8 −8 admin/angel/cjdroute2.c
  7. +1 −1  benc/serialization/json/JsonBencSerializer.c
  8. +5 −5 cmake/modules/RemoteTestTemplate.bash
  9. +1 −1  dht/dhtcore/RouterModule.c
  10. +1 −1  dht/dhtcore/SearchStore.c
  11. +1 −1  interface/ETHInterface_admin.c
  12. +1 −1  interface/SessionManager.c
  13. +1 −1  interface/UDPInterface_admin.c
  14. +7 −3 memory/Allocator.h
  15. +4 −2 memory/BufferAllocator.c
  16. +1 −1  memory/BufferAllocator.h
  17. +22 −5 memory/CanaryAllocator.c
  18. +107 −114 memory/MallocAllocator.c
  19. +7 −1 memory/MallocAllocator.h
  20. +88 −0 memory/MallocAllocator_pvt.h
  21. +3 −0  memory/test/CMakeLists.txt
  22. +44 −0 memory/test/MallocAllocator_oom_test.c
  23. +4 −4 memory/test/MallocAllocator_test.c
  24. +7 −2 util/CMakeLists.txt
  25. +1 −1  util/Pinger.c
  26. +8 −4 util/Pipe.c
  27. +12 −16 util/Process_W32.c
  28. +7 −0 util/Security.c
  29. +2 −0  util/Security.h
  30. +3 −4 util/Security_W32.c
  31. +7 −2 util/test/Process_test.c
View
3  CMakeLists.txt
@@ -203,7 +203,8 @@ add_definitions("-D CJDNS_MAX_PEERS=${CJDNS_MAX_PEERS}")
# make sure casts are done properly.
add_definitions("-D Identity_CHECK=1")
-
+# add in a billion checks which slow things down but catch bugs.
+add_definitions("-D PARANOIA=1")
include_directories(${CMAKE_SOURCE_DIR})
View
4 admin/Admin.c
@@ -123,7 +123,7 @@ static void freeChannel(void* vchannel)
static void newChannel(struct Channel** location, struct Allocator* alloc)
{
- struct Allocator* childAlloc = alloc->child(alloc);
+ struct Allocator* childAlloc = Allocator_child(alloc);
struct Channel* out = childAlloc->clone(sizeof(struct Channel), alloc, &(struct Channel) {
.alloc = childAlloc
});
@@ -396,7 +396,7 @@ static void handleMessage(struct Message* message,
// Try to handle multiple stacked requests in the same frame.
for (;;) {
- struct Allocator* allocator = admin->allocator->child(admin->allocator);
+ struct Allocator* allocator = Allocator_child(admin->allocator);
struct Reader* reader = ArrayReader_new(message->bytes, message->length, allocator);
char nextByte;
View
2  admin/AdminLog.c
@@ -212,7 +212,7 @@ static void subscribe(Dict* args, void* vcontext, String* txid)
} else {
struct Subscription* sub = &log->subscriptions[log->subscriptionCount];
sub->level = level;
- sub->alloc = log->alloc->child(log->alloc);
+ sub->alloc = Allocator_child(log->alloc);
if (file) {
int i;
for (i = 0; i < FILE_NAME_COUNT; i++) {
View
8 admin/Configurator.c
@@ -110,7 +110,7 @@ static void authorizedPasswords(List* list, struct Context* ctx)
String_CONST("authType"), Int_OBJ(1), Dict_CONST(
String_CONST("password"), String_OBJ(passwd), NULL
));
- struct Allocator* child = ctx->alloc->child(ctx->alloc);
+ struct Allocator* child = Allocator_child(ctx->alloc);
rpcCall(String_CONST("AuthorizedPasswords_add"), &args, ctx, child);
child->free(child);
}
@@ -153,7 +153,7 @@ static void udpInterface(Dict* config, struct Context* ctx)
Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes);
- struct Allocator* perCallAlloc = ctx->alloc->child(ctx->alloc);
+ struct Allocator* perCallAlloc = Allocator_child(ctx->alloc);
Dict_putString(value, String_CONST("address"), key, perCallAlloc);
rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc);
perCallAlloc->free(perCallAlloc);
@@ -258,7 +258,7 @@ static void ethInterface(Dict* config, struct Context* ctx)
Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes);
- struct Allocator* perCallAlloc = ctx->alloc->child(ctx->alloc);
+ struct Allocator* perCallAlloc = Allocator_child(ctx->alloc);
Dict_putString(value, String_CONST("macAddress"), key, perCallAlloc);
rpcCall(String_CONST("ETHInterface_beginConnection"), value, ctx, perCallAlloc);
perCallAlloc->free(perCallAlloc);
@@ -300,7 +300,7 @@ void Configurator_config(Dict* config,
struct Log* logger,
struct Allocator* alloc)
{
- struct Allocator* tempAlloc = alloc->child(alloc);
+ struct Allocator* tempAlloc = Allocator_child(alloc);
struct AdminClient* client =
AdminClient_new(sockAddr, addrLen, adminPassword, eventBase, logger, tempAlloc);
View
2  admin/angel/AngelInit.c
@@ -327,7 +327,7 @@ int AngelInit_main(int argc, char** argv)
sendConfToCore(coreIface, alloc, &config, eh, logger);
- struct Allocator* tempAlloc = alloc->child(alloc);
+ struct Allocator* tempAlloc = Allocator_child(alloc);
InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh);
tempAlloc->free(tempAlloc);
View
16 admin/angel/cjdroute2.c
@@ -101,7 +101,7 @@ static bool fileExists(const char* filename)
static String* getCorePath(struct Allocator* alloc)
{
- struct Allocator* alloc2 = alloc->child(alloc);
+ struct Allocator* alloc2 = Allocator_child(alloc);
char* cjdroute2Path = Process_getPath(alloc2);
char* lastSlash = strrchr(cjdroute2Path, '/');
Assert_always(lastSlash != NULL);
@@ -431,13 +431,13 @@ int main(int argc, char** argv)
if (!corePath) {
corePath = getCorePath(allocator);
- }
- if (!corePath) {
- Except_raise(eh, -1, "Can't find a usable cjdns core executable, "
- "try specifying the location in your cjdroute.conf");
- } else {
- Log_warn(logger, "Cjdns core executable was not specified in cjdroute.conf, "
- "guessing its location.");
+ if (!corePath) {
+ Except_raise(eh, -1, "Can't find a usable cjdns core executable, "
+ "try specifying the location in your cjdroute.conf");
+ } else {
+ Log_warn(logger, "Cjdns core executable was not specified in cjdroute.conf, "
+ "guessing its location.");
+ }
}
if (!privateKey) {
View
2  benc/serialization/json/JsonBencSerializer.c
@@ -108,7 +108,7 @@ static inline int parseString(const struct Reader* reader,
#define BUFF_MAX (1<<20)
int curSize = BUFF_SZ;
- struct Allocator* localAllocator = allocator->child(allocator);
+ struct Allocator* localAllocator = Allocator_child(allocator);
uint8_t* buffer = localAllocator->malloc(curSize, localAllocator);
if (readUntil('"', reader) || reader->read(buffer, 1, reader)) {
printf("Unterminated string\n");
View
10 cmake/modules/RemoteTestTemplate.bash
@@ -11,11 +11,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
let line=0
-curl --data-binary @__TEST_FILE__ __REMOTE_TEST_IP_PORT__ 2>>/dev/null \
-| while read x
+for x in `curl --data-binary @__TEST_FILE__ __REMOTE_TEST_IP_PORT__ 2>>/dev/null`
do
- [ "${line}" == "0" ] && echo "$x" | grep '4:codei0e' >/dev/null && exit 1;
+ [ "${line}" == "0" ] && echo "$x" | grep '4:codei0e' >/dev/null && echo 'Passed' && exit 0;
+ echo 'Failed'
echo "$x";
let "line = line + 1"
-done || exit 0;
-exit 1;
+done && exit 1;
+
View
2  dht/dhtcore/RouterModule.c
@@ -1137,7 +1137,7 @@ int RouterModule_pingNode(struct Node* node,
Log_debug(module->logger, "Ping %s\n", addr);
#endif
- struct Allocator* pingAllocator = module->allocator->child(module->allocator);
+ struct Allocator* pingAllocator = Allocator_child(module->allocator);
struct RouterModule_Ping* ping =
pingAllocator->calloc(sizeof(struct RouterModule_Ping), 1, pingAllocator);
*location = ping;
View
2  dht/dhtcore/SearchStore.c
@@ -115,7 +115,7 @@ struct SearchStore_Search* SearchStore_newSearch(
return NULL;
}
- struct Allocator* allocator = store->allocator->child(store->allocator);
+ struct Allocator* allocator = Allocator_child(store->allocator);
struct SearchStore_Search* search =
allocator->calloc(sizeof(struct SearchStore_Search), 1, allocator);
search->searchIndex = i;
View
2  interface/ETHInterface_admin.c
@@ -89,7 +89,7 @@ static void newInterface(Dict* args, void* vcontext, String* txid)
{
struct Context* const ctx = vcontext;
String* const bindDevice = Dict_getString(args, String_CONST("bindDevice"));
- struct Allocator* const alloc = ctx->allocator->child(ctx->allocator);
+ struct Allocator* const alloc = Allocator_child(ctx->allocator);
struct ETHInterface* ethIf = NULL;
struct Jmp jmp;
View
2  interface/SessionManager.c
@@ -89,7 +89,7 @@ struct SessionManager_Session* SessionManager_getSession(uint8_t* lookupKey,
// Make sure cleanup() doesn't get behind.
cleanup(sm);
- struct Allocator* ifAllocator = sm->allocator->child(sm->allocator);
+ struct Allocator* ifAllocator = Allocator_child(sm->allocator);
struct Interface* outsideIf =
ifAllocator->clone(sizeof(struct Interface), ifAllocator, &(struct Interface) {
.sendMessage = sm->encryptedOutgoing,
View
2  interface/UDPInterface_admin.c
@@ -88,7 +88,7 @@ static void newInterface(Dict* args, void* vcontext, String* txid)
{
struct Context* const ctx = vcontext;
String* const bindAddress = Dict_getString(args, String_CONST("bindAddress"));
- struct Allocator* const alloc = ctx->allocator->child(ctx->allocator);
+ struct Allocator* const alloc = Allocator_child(ctx->allocator);
struct UDPInterface* udpIf = NULL;
struct Jmp jmp;
View
10 memory/Allocator.h
@@ -123,10 +123,14 @@ struct Allocator
* Get a new child of this allocator.
* When this allocator is freed all of its children will be freed as well.
*
- * @param this the memory allocator, use allocator->child(allocator) to get a child.
+ * @param this the memory allocator, use Allocator_child(allocator) to get a child.
+ * @param identFile the name of the file where this was called from to aid in debugging.
+ * @param identLine the line number where this was called.
* @return a child allocator.
*/
- struct Allocator* (* const child)(const struct Allocator* this);
+ struct Allocator* (* const child)(const struct Allocator* thisAlloc,
+ const char* identFile,
+ int identLine);
};
#define Allocator_clone(alloc, content) \
@@ -148,7 +152,7 @@ struct Allocator
alloc->realloc(orig, size, alloc)
#define Allocator_child(alloc) \
- alloc->child(alloc)
+ alloc->child(alloc, __FILE__, __LINE__)
#define Allocator_free(alloc) \
alloc->free(alloc)
View
6 memory/BufferAllocator.c
@@ -186,8 +186,10 @@ static bool removeOnFreeJob(void* toRemove, struct Allocator* alloc)
return false;
}
-/** @see Allocator->child() */
-static struct Allocator* childAllocator(const struct Allocator* allocator)
+/** @see Allocator_child() */
+static struct Allocator* childAllocator(const struct Allocator* allocator,
+ const char* identFile,
+ int identLine)
{
return allocator->clone(sizeof(struct Allocator), allocator, &(struct Allocator) {
.context = allocator->context,
View
2  memory/BufferAllocator.h
@@ -22,7 +22,7 @@
* Create a new Allocator which allocates from to a user supplied buffer.
* This allocator will reset the pointer to the beginning of the buffer when
* free() is called on it, it is up to the user to free their buffer.
- * allocator->child(allocator) always returns NULL.
+ * Allocator_child(allocator) always returns NULL.
*
* @param buffer an array to write to.
* @param length the size of the array. If more is written than this length,
View
27 memory/CanaryAllocator.c
@@ -91,6 +91,21 @@ static void* allocatorClone(size_t length, const struct Allocator* allocator, co
return pointer;
}
+/** @see Allocator->onFree() */
+static void* addOnFreeJob(void (* callback)(void* callbackContext),
+ void* callbackContext,
+ const struct Allocator* allocator)
+{
+ struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator);
+ return ctx->alloc->onFree(callback, callbackContext, ctx->alloc);
+}
+
+static bool removeOnFreeJob(void* toRemove, struct Allocator* alloc)
+{
+ struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) alloc);
+ return ctx->alloc->notOnFree(toRemove, ctx->alloc);
+}
+
/** @see Allocator->realloc() */
static void* allocatorRealloc(const void* original,
size_t size,
@@ -116,11 +131,13 @@ static void* allocatorRealloc(const void* original,
return newAllocation(ctx, out, SIZE_INTS(size));
}
-/** @see Allocator->child() */
-static struct Allocator* childAllocator(const struct Allocator* allocator)
+/** @see Allocator_child() */
+static struct Allocator* childAllocator(const struct Allocator* allocator,
+ const char* identFile,
+ int identLine)
{
struct CanaryAllocator_pvt* ctx = Identity_cast((struct CanaryAllocator_pvt*) allocator);
- return CanaryAllocator_new(ctx->alloc->child(ctx->alloc), ctx->rand);
+ return CanaryAllocator_new(ctx->alloc->child(ctx->alloc, identFile, identLine), ctx->rand);
}
/** @see MallocAllocator.h */
@@ -134,8 +151,8 @@ struct Allocator* CanaryAllocator_new(struct Allocator* alloc, struct Random* ra
.clone = allocatorClone,
.realloc = allocatorRealloc,
.child = childAllocator,
- .onFree = alloc->onFree,
- .notOnFree = alloc->notOnFree,
+ .onFree = addOnFreeJob,
+ .notOnFree = removeOnFreeJob,
.context = alloc->context
},
.alloc = alloc,
View
221 memory/MallocAllocator.c
@@ -12,96 +12,74 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define string_strrchr
#include "util/platform/libc/string.h"
#include <stdint.h>
#include <stdio.h>
#include "memory/Allocator.h"
#include "memory/MallocAllocator.h"
-#include "util/Identity.h"
+#include "memory/MallocAllocator_pvt.h"
#include "util/Bits.h"
#include "util/log/Log.h"
-struct OnFreeJob;
-struct OnFreeJob {
- void (* callback)(void* callbackContext);
- void* callbackContext;
- struct OnFreeJob* next;
-};
-
-struct Allocation;
-struct Allocation {
- struct Allocation* next;
- size_t size;
-};
-
-/** Internal state for Allocator. */
-struct Context;
-struct Context
+/** This provides the padding for each line based on the depth in the stack. */
+struct Unroller;
+struct Unroller
{
- /**
- * A linked list of the allocations made with this allocator.
- * These are all freed when the allocator is freed.
- */
- struct Allocation* allocations;
-
- /** A linked list of jobs which must be done when this allocator is freed. */
- struct OnFreeJob* onFree;
-
- /**
- * When this allocator is freed, lastSibling->nextSibling will be set to nextSibling
- * removing this allocator from the linked list.
- * GOTCHYA: if this is the first sibling, lastSibling will point to the parent and
- * in that case, lastSibling->firstChild becomes nextSibling.
- */
- struct Context* lastSibling;
-
- /** A pointer to the next allocator which is a child of the same parent. */
- struct Context* nextSibling;
-
- /** The first child allocator, this will be freed when this allocator is freed. */
- struct Context* firstChild;
-
- /** The number of bytes which can be allocated by this allocator and all of its family. */
- size_t* spaceAvailable;
-
- /** The number of bytes which can be allocated total. */
- size_t maxSpace;
-
- /** This allocator. */
- struct Allocator allocator;
-
- /** For checking structure integrity. */
- Identity
+ const char* const content;
+ const struct Unroller* const last;
};
-
-/** The first ("genesis") allocator, not a child of any other allocator. */
-struct FirstContext
+static void writeUnroller(const struct Unroller* unroller)
{
- /** The context for the first allocator. */
- struct Context context;
-
- /** The actual storage location for the size limit. */
- size_t spaceAvailable;
-};
+ if (unroller) {
+ writeUnroller(unroller->last);
+ fprintf(stderr, "%s", unroller->content);
+ }
+}
+static void unroll(struct MallocAllocator_pvt* context, struct Unroller* unroller)
+{
+ writeUnroller(unroller);
+ const char* ident = (context->identFile) ? strrchr(context->identFile, '/') : " UNKNOWN";
+ ident = ident ? ident + 1 : context->identFile;
+ fprintf(stderr, "%s:%d\n", ident, context->identLine);
+
+ if (context->firstChild) {
+ unroll(context->firstChild, &(struct Unroller) {
+ .content = ((context->nextSibling) ? "| " : " "),
+ .last = unroller
+ });
+ }
+ if (context->nextSibling) {
+ unroll(context->nextSibling, unroller);
+ }
+}
-static void failure(const char* message) Gcc_NORETURN;
-static void failure(const char* message)
+Gcc_NORETURN
+static void failure(struct MallocAllocator_pvt* context, const char* message)
{
+ // get the root allocator.
+ struct MallocAllocator_pvt* rootAlloc = context;
+ while (rootAlloc->lastSibling) {
+ rootAlloc = rootAlloc->lastSibling;
+ }
+ // can't use this allocator because it failed.
+ unroll(rootAlloc, NULL);
+
fprintf(stderr, "Fatal error: %s\n", message);
- abort();
+ exit(0);
}
-static inline void* newAllocation(struct Context* context, size_t size)
+static inline void* newAllocation(struct MallocAllocator_pvt* context, size_t size)
{
- size_t realSize = sizeof(struct Allocation) + size;
+ int64_t realSize = sizeof(struct MallocAllocator_Allocation) + size;
if (*(context->spaceAvailable) <= realSize) {
- failure("Out of memory, limit exceeded.");
+ failure(context, "Out of memory, limit exceeded.");
}
*(context->spaceAvailable) -= realSize;
- struct Allocation* alloc = malloc(realSize);
+ struct MallocAllocator_Allocation* alloc = malloc(realSize);
if (alloc == NULL) {
- failure("Out of memory, malloc() returned NULL.");
+ failure(context, "Out of memory, malloc() returned NULL.");
}
alloc->next = context->allocations;
alloc->size = realSize;
@@ -112,20 +90,20 @@ static inline void* newAllocation(struct Context* context, size_t size)
/** @see Allocator->free() */
static void freeAllocator(const struct Allocator* allocator)
{
- struct Context* context = Identity_cast((struct Context*) allocator->context);
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) allocator);
// Do the onFree jobs.
- struct OnFreeJob* job = context->onFree;
+ struct MallocAllocator_OnFreeJob* job = context->onFree;
while (job != NULL) {
job->callback(job->callbackContext);
job = job->next;
}
// Free all of the child allocators.
- struct Context* child = context->firstChild;
+ struct MallocAllocator_pvt* child = context->firstChild;
while (child != NULL) {
- struct Context* nextChild = child->nextSibling;
- freeAllocator(&child->allocator);
+ struct MallocAllocator_pvt* nextChild = child->nextSibling;
+ freeAllocator(&child->pub);
child = nextChild;
}
@@ -137,17 +115,17 @@ static void freeAllocator(const struct Allocator* allocator)
context->lastSibling->firstChild == context) {
context->lastSibling->firstChild = context->nextSibling;
} else if (context->lastSibling != NULL) {
- failure("The last sibling of this allocator has no reference to it.");
+ failure(context, "The last sibling of this allocator has no reference to it.");
}
if (context->nextSibling != NULL) {
context->nextSibling->lastSibling = context->lastSibling;
}
// Free all of the allocations including the one which holds the allocator.
- struct Allocation* loc = context->allocations;
+ struct MallocAllocator_Allocation* loc = context->allocations;
while (loc != NULL) {
*(context->spaceAvailable) += loc->size;
- struct Allocation* nextLoc = loc->next;
+ struct MallocAllocator_Allocation* nextLoc = loc->next;
#ifdef Log_DEBUG
Bits_memset(loc, 0xff, loc->size);
#endif
@@ -159,13 +137,14 @@ static void freeAllocator(const struct Allocator* allocator)
/** @see Allocator->malloc() */
static void* allocatorMalloc(size_t length, const struct Allocator* allocator)
{
- return newAllocation(allocator->context, length);
+ struct MallocAllocator_pvt* ctx = Identity_cast((struct MallocAllocator_pvt*) allocator);
+ return newAllocation(ctx, length);
}
/** @see Allocator->calloc() */
static void* allocatorCalloc(size_t length, size_t count, const struct Allocator* allocator)
{
- void* pointer = allocator->malloc(length * count, allocator);
+ void* pointer = allocatorMalloc(length * count, allocator);
Bits_memset(pointer, 0, length * count);
return pointer;
}
@@ -173,7 +152,7 @@ static void* allocatorCalloc(size_t length, size_t count, const struct Allocator
/** @see Allocator->clone() */
static void* allocatorClone(size_t length, const struct Allocator* allocator, const void* toClone)
{
- void* pointer = allocator->malloc(length, allocator);
+ void* pointer = allocatorMalloc(length, allocator);
Bits_memcpy(pointer, toClone, length);
return pointer;
}
@@ -187,13 +166,15 @@ static void* allocatorRealloc(const void* original,
return allocatorMalloc(size, allocator);
}
- struct Context* context = Identity_cast((struct Context*) allocator->context);
- struct Allocation** locPtr = &context->allocations;
- struct Allocation* origLoc = ((struct Allocation*) original) - 1;
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) allocator);
+ struct MallocAllocator_Allocation** locPtr = &context->allocations;
+ struct MallocAllocator_Allocation* origLoc =
+ ((struct MallocAllocator_Allocation*) original) - 1;
for (;;) {
- struct Allocation* loc = *locPtr;
+ struct MallocAllocator_Allocation* loc = *locPtr;
if (loc == NULL) {
- failure("Reallocation of memory which was not allocated using this allocator.");
+ failure(context,
+ "Reallocation of memory which was not allocated using this allocator.");
}
if (loc == origLoc) {
break;
@@ -201,19 +182,19 @@ static void* allocatorRealloc(const void* original,
locPtr = &loc->next;
}
- struct Allocation* nextLoc = origLoc->next;
+ struct MallocAllocator_Allocation* nextLoc = origLoc->next;
- size_t realSize = sizeof(struct Allocation) + size;
+ size_t realSize = sizeof(struct MallocAllocator_Allocation) + size;
if (*(context->spaceAvailable) + origLoc->size < realSize) {
- failure("Out of memory, limit exceeded.");
+ failure(context, "Out of memory, limit exceeded.");
}
*(context->spaceAvailable) += origLoc->size;
*(context->spaceAvailable) -= realSize;
- struct Allocation* alloc = realloc(origLoc, realSize);
+ struct MallocAllocator_Allocation* alloc = realloc(origLoc, realSize);
if (alloc == NULL) {
- failure("Out of memory, realloc() returned NULL.");
+ failure(context, "Out of memory, realloc() returned NULL.");
}
alloc->next = nextLoc;
alloc->size = realSize;
@@ -221,20 +202,24 @@ static void* allocatorRealloc(const void* original,
return (void*) (alloc + 1);
}
-/** @see Allocator->child() */
-static struct Allocator* childAllocator(const struct Allocator* allocator)
+/** @see Allocator_child() */
+static struct Allocator* childAllocator(const struct Allocator* allocator,
+ const char* identFile,
+ int identLine)
{
- struct Context* context = Identity_cast((struct Context*) allocator->context);
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) allocator);
- if (*(context->spaceAvailable) <= sizeof(struct FirstContext)) {
- failure("Out of memory, limit exceeded.");
+ uint32_t allocSize =
+ sizeof(struct MallocAllocator_FirstCtx) + sizeof(struct MallocAllocator_Allocation);
+ if (*(context->spaceAvailable) <= allocSize) {
+ failure(context, "Out of memory, limit exceeded.");
}
- struct Allocator* childAlloc = MallocAllocator_new(0);
+ struct Allocator* childAlloc = MallocAllocator_new(allocSize);
- *(context->spaceAvailable) -= (sizeof(struct FirstContext) + sizeof(struct Allocation));
+ *(context->spaceAvailable) -= allocSize;
- struct Context* child = (struct Context*) childAlloc->context;
+ struct MallocAllocator_pvt* child = (struct MallocAllocator_pvt*) childAlloc;
child->maxSpace = context->maxSpace;
child->lastSibling = context;
child->nextSibling = context->firstChild;
@@ -242,6 +227,8 @@ static struct Allocator* childAllocator(const struct Allocator* allocator)
context->firstChild->lastSibling = child;
}
child->spaceAvailable = context->spaceAvailable;
+ child->identFile = identFile;
+ child->identLine = identLine;
context->firstChild = child;
return childAlloc;
@@ -250,16 +237,16 @@ static struct Allocator* childAllocator(const struct Allocator* allocator)
/** @see Allocator->onFree() */
static void* addOnFreeJob(void (* callback)(void* callbackContext),
void* callbackContext,
- const struct Allocator* this)
+ const struct Allocator* allocator)
{
- struct Context* context = Identity_cast((struct Context*) this->context);
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) allocator);
- struct OnFreeJob* newJob =
- this->calloc(sizeof(struct OnFreeJob), 1, this);
+ struct MallocAllocator_OnFreeJob* newJob =
+ allocatorCalloc(sizeof(struct MallocAllocator_OnFreeJob), 1, allocator);
newJob->callback = callback;
newJob->callbackContext = callbackContext;
- struct OnFreeJob* job = context->onFree;
+ struct MallocAllocator_OnFreeJob* job = context->onFree;
if (job == NULL) {
context->onFree = newJob;
} else {
@@ -273,8 +260,8 @@ static void* addOnFreeJob(void (* callback)(void* callbackContext),
static bool removeOnFreeJob(void* toRemove, struct Allocator* alloc)
{
- struct Context* context = Identity_cast((struct Context*) alloc->context);
- struct OnFreeJob** jobPtr = &(context->onFree);
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) alloc);
+ struct MallocAllocator_OnFreeJob** jobPtr = &(context->onFree);
while (*jobPtr != NULL) {
if (*jobPtr == toRemove) {
*jobPtr = (*jobPtr)->next;
@@ -286,18 +273,24 @@ static bool removeOnFreeJob(void* toRemove, struct Allocator* alloc)
}
/** @see MallocAllocator.h */
-struct Allocator* MallocAllocator_new(size_t sizeLimit)
+struct Allocator* MallocAllocator_newWithIdentity(size_t sizeLimit,
+ const char* identFile,
+ int identLine)
{
- struct FirstContext stackContext = {
+ struct MallocAllocator_FirstCtx stackContext = {
.spaceAvailable = (sizeLimit == 0) ? SIZE_MAX : sizeLimit +
- sizeof(struct FirstContext) + sizeof(struct Allocator)
+ sizeof(struct MallocAllocator_FirstCtx) + sizeof(struct Allocator),
+ .context = {
+ .identFile = identFile,
+ .identLine = identLine
+ }
};
stackContext.context.spaceAvailable = &stackContext.spaceAvailable;
- struct FirstContext* firstContext =
- newAllocation(&stackContext.context, sizeof(struct FirstContext));
- Bits_memcpyConst(firstContext, &stackContext, sizeof(struct FirstContext));
- struct Context* context = &firstContext->context;
+ struct MallocAllocator_FirstCtx* firstContext =
+ newAllocation(&stackContext.context, sizeof(struct MallocAllocator_FirstCtx));
+ Bits_memcpyConst(firstContext, &stackContext, sizeof(struct MallocAllocator_FirstCtx));
+ struct MallocAllocator_pvt* context = &firstContext->context;
context->spaceAvailable = &firstContext->spaceAvailable;
context->maxSpace = firstContext->spaceAvailable;
@@ -313,13 +306,13 @@ struct Allocator* MallocAllocator_new(size_t sizeLimit)
.notOnFree = removeOnFreeJob
};
- Bits_memcpyConst(&context->allocator, &allocator, sizeof(struct Allocator));
+ Bits_memcpyConst(&context->pub, &allocator, sizeof(struct Allocator));
Identity_set(context);
- return &context->allocator;
+ return &context->pub;
}
size_t MallocAllocator_bytesAllocated(struct Allocator* allocator)
{
- struct Context* context = Identity_cast((struct Context*) allocator->context);
+ struct MallocAllocator_pvt* context = Identity_cast((struct MallocAllocator_pvt*) allocator);
return context->maxSpace - *context->spaceAvailable;
}
View
8 memory/MallocAllocator.h
@@ -23,8 +23,14 @@
* @param sizeLimit the number of bytes which are allowed to be allocated by
* this allocator or any of its children before the program
* will be halted with an error.
+ * @param identFile the file where this allocator was created.
+ * @param identLine the line where this was called from.
*/
-struct Allocator* MallocAllocator_new(size_t sizeLimit);
+struct Allocator* MallocAllocator_newWithIdentity(size_t sizeLimit,
+ const char* identFile,
+ int identLine);
+#define MallocAllocator_new(sl) \
+ MallocAllocator_newWithIdentity((sl), __FILE__, __LINE__)
/**
* Get the number of bytes allocated so far by this allocator,
View
88 memory/MallocAllocator_pvt.h
@@ -0,0 +1,88 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MallocAllocator_pvt_H
+#define MallocAllocator_pvt_H
+
+#include "memory/MallocAllocator.h"
+#include "util/Identity.h"
+
+struct MallocAllocator_OnFreeJob;
+struct MallocAllocator_OnFreeJob {
+ void (* callback)(void* callbackContext);
+ void* callbackContext;
+ struct MallocAllocator_OnFreeJob* next;
+};
+
+struct MallocAllocator_Allocation;
+struct MallocAllocator_Allocation {
+ struct MallocAllocator_Allocation* next;
+ size_t size;
+};
+
+/** Internal state for Allocator. */
+struct MallocAllocator_pvt;
+struct MallocAllocator_pvt
+{
+ /** This allocator. */
+ struct Allocator pub;
+
+ /**
+ * A linked list of the allocations made with this allocator.
+ * These are all freed when the allocator is freed.
+ */
+ struct MallocAllocator_Allocation* allocations;
+
+ /** A linked list of jobs which must be done when this allocator is freed. */
+ struct MallocAllocator_OnFreeJob* onFree;
+
+ /**
+ * When this allocator is freed, lastSibling->nextSibling will be set to nextSibling
+ * removing this allocator from the linked list.
+ * GOTCHYA: if this is the first sibling, lastSibling will point to the parent and
+ * in that case, lastSibling->firstChild becomes nextSibling.
+ */
+ struct MallocAllocator_pvt* lastSibling;
+
+ /** A pointer to the next allocator which is a child of the same parent. */
+ struct MallocAllocator_pvt* nextSibling;
+
+ /** The first child allocator, this will be freed when this allocator is freed. */
+ struct MallocAllocator_pvt* firstChild;
+
+ /** The number of bytes which can be allocated by this allocator and all of its family. */
+ int64_t* spaceAvailable;
+
+ /** The number of bytes which can be allocated total. */
+ size_t maxSpace;
+
+ /** This is the location where the allocator was created. */
+ const char* identFile;
+ int identLine;
+
+ /** For checking structure integrity. */
+ Identity
+};
+
+/** The first ("genesis") allocator, not a child of any other allocator. */
+struct MallocAllocator_FirstCtx
+{
+ /** The context for the first allocator. */
+ struct MallocAllocator_pvt context;
+
+ /** The actual storage location for the size limit. */
+ int64_t spaceAvailable;
+};
+
+#endif
View
3  memory/test/CMakeLists.txt
@@ -12,9 +12,12 @@
set(Test_FILES
CanaryAllocator_test.c
MallocAllocator_test.c
+ MallocAllocator_oom_test.c
)
set(Test_LIBRARIES
cjdmemory
cjdns-memory-canary
+ cjdns-crypto-random
+ util # security
)
include(${CMAKE_SOURCE_DIR}/cmake/modules/Test.cmake)
View
44 memory/test/MallocAllocator_oom_test.c
@@ -0,0 +1,44 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "crypto/Random.h"
+#include "memory/Allocator.h"
+#include "memory/MallocAllocator.h"
+#include "util/Assert.h"
+#include "util/Security.h"
+
+void overflow(struct Allocator* alloc, struct Random* rand)
+{
+ uint32_t x = Random_uint32(rand);
+ for (int i = 0; i < 32; i++) {
+ struct Allocator* a = Allocator_child(alloc);
+ uint32_t count = ((x>>i) & 31);
+ while (count--) {
+ a = Allocator_child(alloc);
+ if (count == 27) {
+ overflow(a, rand);
+ }
+ }
+ }
+}
+
+int main()
+{
+ Security_maxMemory(1<<20, NULL);
+ struct Allocator* alloc = MallocAllocator_new(1<<19);
+ struct Random* rand = Random_new(alloc, NULL);
+ overflow(alloc, rand);
+ // sometimes it doesn't use up all of it's space.
+ //Assert_always(0);
+}
View
8 memory/test/MallocAllocator_test.c
@@ -18,10 +18,10 @@
#include <stdio.h>
#include "memory/Allocator.h"
-#include "memory/MallocAllocator.c"
+#include "memory/MallocAllocator_pvt.h"
-#define ALLOCATION_SIZE sizeof(struct Allocation)
-#define ALLOCATOR_SIZE sizeof(struct FirstContext)
+#define ALLOCATION_SIZE sizeof(struct MallocAllocator_Allocation)
+#define ALLOCATOR_SIZE sizeof(struct MallocAllocator_FirstCtx)
int main()
{
@@ -33,7 +33,7 @@ int main()
bytesUsed += 25 + ALLOCATION_SIZE;
Assert_always(MallocAllocator_bytesAllocated(alloc) == bytesUsed);
- struct Allocator* child = alloc->child(alloc);
+ struct Allocator* child = Allocator_child(alloc);
bytesUsed += ALLOCATION_SIZE + ALLOCATOR_SIZE;
Assert_always(MallocAllocator_bytesAllocated(alloc) == bytesUsed);
View
9 util/CMakeLists.txt
@@ -18,20 +18,25 @@ add_subdirectory(events)
add_subdirectory(platform)
find_package(Libevent2 REQUIRED)
-include_directories(${LIBEVENT2_INCLUDE_DIRS})
+find_package(Socket REQUIRED)
+
+add_library(cjdns-errno Errno.c)
if(WIN32)
set(sec Security_W32.c)
+ target_link_libraries(cjdns-errno ${SOCKET_LIBRARIES})
else()
set(sec Security.c)
endif()
+
add_library(cjdns-security
${sec}
)
target_link_libraries(cjdns-security
cjdns-except
+ cjdns-errno
)
add_library(cjdns-process
@@ -40,7 +45,6 @@ add_library(cjdns-process
add_library(util
AverageRoller.c
- Errno.c
Hex.c
Pinger.c
Pipe.c
@@ -53,6 +57,7 @@ target_link_libraries(util
${LIBEVENT2_LIBRARIES}
cjdns-security
cjdns-util-log-writer
+ cjdns-errno
)
# Everything must be tested.
View
2  util/Pinger.c
@@ -77,7 +77,7 @@ struct Pinger_Ping* Pinger_newPing(String* data,
return NULL;
}
- struct Allocator* alloc = pinger->allocator->child(pinger->allocator);
+ struct Allocator* alloc = Allocator_child(pinger->allocator);
// Prefix the data with the slot number.
String* toSend = String_newBinary(NULL, ((data) ? data->len : 0) + 4, alloc);
View
12 util/Pipe.c
@@ -17,22 +17,26 @@
#include <unistd.h>
#ifdef WIN32
-#include <windows.h>
+ #include <windows.h>
+ #include <io.h>
+ #include <fcntl.h>
+ #define pipe(fds) _pipe(fds, 65535, _O_BINARY)
#endif
int Pipe_createUniPipe(int fds[2])
{
+/*
#ifdef WIN32
HANDLE readHandle, writeHandle;
- /* XXX: Security context for inheritance? */
+ // XXX: Security context for inheritance?
if (!CreatePipe(&readHandle, &writeHandle, NULL, 0)) {
return 1;
}
fds[0] = _open_osfhandle((intptr_t)readHandle, 0);
fds[1] = _open_osfhandle((intptr_t)writeHandle, 0);
- /* TODO These should eventually need to be closed with _close */
+ // TODO These should eventually need to be closed with _close
return 0;
#else
+*/
return pipe(fds);
-#endif
}
View
28 util/Process_W32.c
@@ -14,38 +14,34 @@
*/
#define string_strcpy
#define string_strlen
-#include "memory/Allocator.h"
-#include "memory/MallocAllocator.h"
#include "util/platform/libc/string.h"
#include "util/Process.h"
#include "util/Bits.h"
+#include "wire/Message.h"
#include <windows.h>
int Process_spawn(char* binaryPath, char** args)
{
- size_t len = 0;
+ struct Message* msg;
+ Message_STACK(msg, 0, 1024);
+
+ Message_push(msg, "\0", 1);
+
for (char** iter = args; *iter; ++iter) {
- len += strlen(*iter) + 1;
- }
- char* command = NULL;
- if (len) {
- struct Allocator* alloc = MallocAllocator_new(len);
- command = alloc->calloc(len, 1, alloc);
- len = 0;
- for (char** iter = args; *iter; ++iter) {
- strcpy(command + len, *iter);
- len += strlen(*iter) + 1;
- }
+ Message_push(msg, *iter, strlen(*iter));
+ Message_push(msg, " ", 1);
}
+
STARTUPINFO si;
PROCESS_INFORMATION pi;
Bits_memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
Bits_memset(&pi, 0, sizeof(pi));
- if (!CreateProcessA(binaryPath, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ if (!CreateProcessA(binaryPath, (char*)msg->bytes, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+ {
return -1;
}
CloseHandle(pi.hProcess);
@@ -60,7 +56,7 @@ char* Process_getPath(struct Allocator* alloc)
if (!len || len == 1023) {
return NULL;
}
- char* out = alloc->calloc(len + 1, 1, alloc);
+ char* out = Allocator_calloc(alloc, len + 1, 1);
Bits_memcpy(out, buf, len);
return out;
}
View
7 util/Security.c
@@ -53,3 +53,10 @@ void Security_noFiles(struct Except* eh)
Except_raise(eh, -1, "Failed to set open file limit to zero [%s]", Errno_getString());
}
}
+
+void Security_maxMemory(uint32_t max, struct Except* eh)
+{
+ if (setrlimit(RLIMIT_AS, &(struct rlimit){ max, max })) {
+ Except_raise(eh, -1, "Failed to limit available memory [%s]", Errno_getString());
+ }
+}
View
2  util/Security.h
@@ -26,4 +26,6 @@ void Security_setUser(char* userName, struct Log* logger, struct Except* eh);
void Security_noFiles(struct Except* eh);
+void Security_maxMemory(uint32_t maxMemory, struct Except* eh);
+
#endif
View
7 util/Security_W32.c
@@ -12,9 +12,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef W32Security_H
-#define W32Security_H
-
#include "exception/Except.h"
#include "util/Security.h"
#include "util/log/Log.h"
@@ -29,4 +26,6 @@ void Security_noFiles(struct Except* eh)
{
}
-#endif
+void Security_maxMemory(uint32_t max, struct Except* eh)
+{
+}
View
9 util/test/Process_test.c
@@ -43,8 +43,12 @@ int main(int argc, char** argv)
struct Allocator* alloc = MallocAllocator_new(1<<20);
char* path = Process_getPath(alloc);
Assert_true(path != NULL);
- Assert_true(strstr(path, "/Process_test"));
- Assert_true(path[0] == '/');
+ #ifdef WIN32
+ Assert_true(strstr(path, ":\\") == path + 1); /* C:\ */
+ Assert_true(strstr(path, ".exe"));
+ #else
+ Assert_true(path[0] == '/');
+ #endif
int fds[2];
Assert_true(!Pipe_createUniPipe(fds));
@@ -54,6 +58,7 @@ int main(int argc, char** argv)
char* args[] = { fdName, NULL };
Assert_true(!Process_spawn(path, args));
+
char output[32] = {0};
ssize_t len = read(fds[0], output, 31);
Assert_true(len == strlen(MESSAGE));
Please sign in to comment.
Something went wrong with that request. Please try again.