wiki:CodingGuidelines

Memory Allocation Guidelines

In MapServer 6.0, 3 new functions have been introduced to handle memory allocations safely:

  • msSmallMalloc()
  • msSmallRealloc()
  • msSmallCalloc()

Their purpose is to allocate memory the same way malloc(), realloc() and calloc() do. Hovewer, those functions are considered safe because if the memory allocation fail, they will report the failure to stderr and terminate the program. The reason of the Small in their names is because they should be used for small allocations (ie. strings). We consider that if the system fails to allocate small memory allocations, it is in a very bad state and that we can't terminate the program in a cleaner manner. Big allocations should be handled manually and should return a failure code to let mapserver cleans its things and exit. There are also 2 new macros defined to check a memory allocation, report the error using msSetError() and return accordingly:

  • MS_CHECK_ALLOC()
  • MS_CHECK_ALLOC_NO_RET()

When you add memory allocations in a function, here's how you should determine how to check the allocation:

If the function can return a failure code. (Be careful.. sometime the function can return a failure code but it is not necessary always checked everywhere, although normally they are. If the function was already returning failure code.. you can assume it is checked properly.)

  1. If there is a cleanup to do: (Previous memory allocations, etc.) Handle it manually, doing the proper cleanup and return the failure code.
    geometryList->geometries = (gmlGeometryObj *) malloc(sizeof(gmlGeometryObj)*geometryList->numgeometries);
    if (geometryList->geometries ==  NULL)
    {
        msSetError(MS_MEMERR, "Out of memory allocating %u bytes.\n", "msGMLGetGeometries()", 
                   sizeof(gmlGeometryObj)*geometryList->numgeometries);
        free(geometryList);
        return NULL;
    }
    
  2. If there is no cleanup to do: Add a MS_CHECK_ALLOC() after the allocation.
      namespaceList = (gmlNamespaceListObj *) malloc(sizeof(gmlNamespaceListObj)); 
      MS_CHECK_ALLOC(namespaceList, sizeof(gmlNamespaceListObj), NULL);
    

The last parameter is the failure code to return. Note that in some cases, you may need MS_CHECK_ALLOC_NO_RET(), which do the same thing than MS_CHECK_ALLOC(), but returns nothing.

Note that you can always consider the use of msSmall* functions if the memory allocations are relatively small or that the complexity of the code makes things hard to be done cleanly. In those cases, just replace the malloc/realloc/calloc calls by the appropriate msSmall* functions.

String Manipulation Guidelines

This is essentially to avoid buffer overflows.

Basic rules:

  • Always use snprintf() rather than sprintf().
  • Always use strlcpy() and strlcat() rather than strcpy/strncpy and strcat/strncat. strlcpy and strlcat are different than strncpy/strncat. They are better. Unlike strncpy/strncat functions, strlcpy() and strlcat() take the full size of the buffer (not just the length) and guarantee to NUL-terminate the result. See http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy&sektion=3 for more details. Here's an example to use them:
    strlcpy(columns_wanted, geom_column_name, sizeof(columns_wanted)); // the string is always nul-terminated. 
    
    strlcat(result,geom_table, buffer_size); 
    strlcat(result,box3d, buffer_size); // we always pass the full size of the buffer!
    strlcat(result,end, buffer_size); 
    
  • Always use msStrdup() rather than strdup(). msStrdup is a safe version of strdup. Since almost everything passed to it are small strings, if the memory allocation fails, it will report the error and terminate the program.
Last modified 6 years ago Last modified on Nov 29, 2010 10:22:38 AM