2

I am developing code to use in the COOJA simulator. I used malloc() for all of the dynamic memory allocations. While the simulation is running, COOJA motes restart periodically and at last I get an error which tells me the reason is I'm using malloc().

I'm thinking of using Contiki's specific memory allocation class named "mmem". I could not found any example of using it. Here is an example in which I used malloc() to allocate memory to a string named sent.

How do I replace using malloc() to use mmem instead of malloc()?

   char *sent;
   sent = (char*)malloc(120);
   strncpy(sent , "example" , 7);
   strncat(sent , "|", 1);
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
mahshid
  • 41
  • 7
  • Why dont you just allocate 120 bytes on the stack? – Morten Jensen Jul 20 '19 at 13:33
  • in my case, there would be a lot of conversion between character and string, which I'm not interested in. – mahshid Jul 20 '19 at 16:58
  • I don’t think I understand. If you know the allocation size upfront (which your example code suggests), why not just allocate on the stack? Embedded development on low-resource devices and dynamic allocation usually ends with fragmentation which leads to exhaustion, which may be what caused your crash. Even Contiki’s documentation mentions this. Nonetheless, I assume you’ve read this guide: https://github.com/contiki-os/contiki/wiki/Memory-allocation#The_mmem_Managed_Memory_Allocator ? – Morten Jensen Jul 20 '19 at 17:35
  • I am not sure if I completely understand the solution that you're refering to. would you please explain how I can allocate on the stack? honestly I don't understand what you meant by "stack". – mahshid Jul 20 '19 at 20:18
  • stack vs heap is a central concept in C programming and I’ll have a hard time explaining it here in only 600 characters. Basically instead of `char* sent = malloc(120);` you do `char sent[120];` etc. – Morten Jensen Jul 20 '19 at 21:31
  • the code's logic is working with strings. strings would be sent and received, concatenated and edited a lot. by using ```char sent[120]```, I should deal with 120 characters and change it to string and change it back many times. I chose pointers instead of arrays to make it simple to work with strings and avoid complexity. – mahshid Jul 21 '19 at 05:35
  • In C a char-array is a string? In `char sent[120];`, `sent` is a char-pointer just as well as if you had done `char* sent = malloc(120);`. The memory is just allocated on the stack instead of the heap. – Morten Jensen Jul 21 '19 at 07:54
  • I'm new to C, so I don't understand what happens with heap or stack. but I learnt that we represent a string using a char array from here : [ https://www.tutorialspoint.com/cprogramming/c_strings ] . Am I wrong? – mahshid Jul 21 '19 at 10:51
  • That is exactly my point: a string is a char-array whether it is allocated on the stack or on the heap. Heap allocation is just a bad idea on resource-constrained devices, so I advise you to allocate statically instead, regardless of any perceived simplicity-benefits from dynamic allocation. – Morten Jensen Jul 21 '19 at 11:20

1 Answers1

2

From Contiki’s github Wiki

Here is an example of how to use the managed memory allocator:

 #include "contiki.h"
 #include "lib/mmem.h"

 static struct mmem mmem;

 static void
 test_mmem(void)
 {
   struct my_struct {
     int a;
   } my_data, *my_data_ptr;

   if(mmem_alloc(&mmem, sizeof(my_data)) == 0) {
     printf("memory allocation failed\n");
   } else {
     printf("memory allocation succeeded\n");
     my_data.a = 0xaa;
     memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data));
     /* The cast below is safe only if the struct is packed */
     my_data_ptr = (struct my_struct *)MMEM_PTR(&mmem);
     printf("Value a equals 0x%x\n", my_data_ptr->a);
     mmem_free(&mmem);
   }
 }

The example above shows a basic example of how the managed memory library can be used. On line 4, we allocate a variable, mmem, that identifies the managed memory object that we are about to allocate. On line 13, we use the mmem variable as an argument for mmem_alloc() to allocate space for a structure of sizeof(my_data) bytes. If the allocation succeeded, we copy the values from an existing structure into the allocated structure, pointed to by MMEM_PTR(&mmem). Individual members of allocated structure can then be accessed by a type cast of MMEM_PTR(&mmem) to struct my_struct *, as shown on line 20. Note that the cast is only safe if the struct is packed. The managed memory is finally deallocated on line 21 by calling mmem_free().

.

EDIT:

From the code you've pasted in the comments, there is no need to use malloc or the mmem-module. Just allocate on the stack. Maybe try something like this instead:

/* Allocate memory on the stack */
char sent[120];

/* Manipulate strings */
strncpy(sent , "reqid" , 5); 
strncat(sent, "|", 1); 

/* Send UDP packet */
uip_udp_packet_send(mcast_conn, sent, strlen(sent)); 

/* Print out string sent */
printf(" (msg: %s)\n", sent); 

EDIT 2:

Here is a page on heap vs stack. and here is a stackoverflow question about dynamic allocation on embedded devices and the problems it involves.

Morten Jensen
  • 5,818
  • 3
  • 43
  • 55
  • actually I saw this example. to clarify the problem I insert my code here: ` struct my_struct { char * sent; } my_data, *my_data_ptr; strncpy(my_data.sent , "reqid" , 5); strncat(my_data.sent, "|", 1); memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data)); my_data_ptr = (struct my_struct *)MMEM_PTR(&mmem); uip_udp_packet_send(mcast_conn, my_data_ptr->sent, strlen(my_data_ptr->sent)); printf(" (msg: %s)\n", my_data_ptr->sent); mmem_free(&mmem);` I expect to see "mg : reqid|" in the output but the output in NULL. I want to know where I am doing wrong. – mahshid Jul 20 '19 at 20:11
  • @mahshid Can you please edit your question to include the code you’ve tried? You are missing a call to `mmem_init()` and `mmem_alloc(...)` I think...? Again I suggest you try using static allocation instead of dynamic allocation, for the reasons mentioned in my other comments (fragmentation leading to memory exhaustion). – Morten Jensen Jul 20 '19 at 21:46
  • sorry for the bad representation, I tried several times but I could not understand how it works.I added mmem_init() and mmem_allocate() but it's still the same. ```C struct my_struct { char * sent; } my_data, *my_data_ptr; mmem_init(); mmem_alloc(&mmem, 120); strncpy(my_data.sent , "reqid" , 5); strncat(my_data.sent, "|", 1); memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data)); my_data_ptr = (struct my_struct *)MMEM_PTR(&mmem); uip_udp_packet_send(mcast_conn, my_data_ptr->sent, strlen(my_data_ptr->sent)); printf(" (msg: %s)\n", my_data_ptr->sent); mmem_free(&mmem); ``` – mahshid Jul 21 '19 at 05:24
  • @mahshid I have updated my answer with some code I think could work instead. I don't have anything running Contiki, so I can't test it myself, but I don't think you need the `mmem`-module from what you've posted. – Morten Jensen Jul 21 '19 at 11:32