0

I am writing a C program with the nDPI library, available here. (Coding on a Ubuntu machine, GCC compiler, nDPI version 3.2) nDPI is used to inspect network traffic. The code uses a lot of different structs to represent network stuff, like network flows, network protocols, network hosts, and so on.

So I think that if you want to create these structs, you must use the library's custom malloc() and free() functions, which makes sense. But I'm having a hard time understanding the function prototypes. Here's a few relevant lines of code from the API header file:

/* Utility functions to set ndpi malloc/free/print wrappers */

void set_ndpi_flow_malloc(void* (*__ndpi_flow_malloc)(size_t size));

void set_ndpi_flow_free(void (*__ndpi_flow_free)(void *ptr));

Consider the set_ndpi_flow_malloc() function. Elsewhere in the source code, there is a struct nDPI_flow_info defined, and I see that struct used everywhere in the code. So I assume set_ndpi_flow_malloc() is to allocate one of these structs on the heap, populate it with some information maybe, and return the pointer.

But I don't understand the arguments into this function. If I had to guess, I'd say that set_ndpi_flow_malloc() accepts a pointer to another function, called __ndpi_flow_malloc(), and that function takes a size_t integer as an argument. Turns out, there's this function prototype elsewhere in the API header file:

void * ndpi_flow_malloc(size_t size);

That's kind of the function I need: I need __ndpi_flow_malloc() (two underline characters on the front of the name) What do those double underlines mean?

Another question... if set_ndpi_flow_malloc() is a custom malloc() function, shouldn't it return a pointer to the allocated memory?

Another question... How would I actually write this in my code? Like this...?

struct nDPI_flow_info* myFlow;

set_ndpi_flow_malloc( (void*) &ndpi_flow_malloc( sizeof( struct nDPI_flow_info )) );

// ...use the struct...

set_ndpi_flow_free( &ndpi_flow_free* myFlow ) );

That can't be right. I don't understand how the second line returns the pointer and assigns it to variable myFlow.

Any advice or criticism is wildly appreciated. Thanks!

FULL DISCLOSURE :: I have also posted this question here.

Pete
  • 1,511
  • 2
  • 26
  • 49

2 Answers2

2

The function set_ndpi_flow_malloc doesn't actually do the allocation but allows you to set the function that does. It's argument is a pointer to a function that takes a size_t and returns a void *, and the name of the argument is __ndpi_flow_malloc.

The same goes for set_ndpi_flow_free. It tells the library which function to use as its custom free function.

Most likely, ndpi_flow_malloc is the default custom allocator. So if this is the one you want to use you would do the following to set it as the custom allocation function:

set_ndpi_flow_malloc(ndpi_flow_malloc);

Then assuming there is a similar default free function called ndpi_flow_free, you would do this to set it as the custom free function:

set_ndpi_flow_free(ndpi_flow_free);
dbush
  • 205,898
  • 23
  • 218
  • 273
2

I'm not familiar with this API, but based on what you've posted here it must allocate memory internally to perform some operations, and it allows you to specify which allocator/deallocator it should use to do that - it can either use vanilla malloc and free to allocate and deallocate memory, or you can pass a custom allocator/deallocator that uses a different allocation scheme or is instrumented for logging/debugging or whatever.

To make this easier to read, I'm going to rename things. Basically pretend I've done

#define SNFM set_ndpi_flow_malloc
#define NFM  __ndpi_flow_malloc

That leaves us with

void SNFM(void *(*NFM)(size_t size));

which is read as

     SNFM                               -- SNFM
     SNFM(                         )    -- is a function taking
     SNFM(        NFM              )    --   parameter NFM
     SNFM(      (*NFM)             )    --   is a pointer to
     SNFM(      (*NFM)(           ))    --     a function taking
     SNFM(      (*NFM)(       size))    --       parameter size
     SNFM(      (*NFM)(size_t size))    --       is a size_t
     SNFM(     *(*NFM)(size_t size))    --     returning a pointer to
     SNFM(void *(*NFM)(size_t size))    --       void
void SNFM(void *(*NFM)(size_t size));   -- returning void

So basically, the argument to set_ndpi_flow_malloc is a pointer to a function that takes a size_t and returns a pointer to void - i.e., malloc or a function with the same signature that does the same thing:

set_ndpi_flow_malloc( malloc );

or

void *my_malloc( size_t size )
{
  ...
}
...
set_ndpi_flow_malloc( my_malloc );

This function doesn't allocate memory; instead, it's how you specify which allocator to use when the library needs to allocate memory internally. set_ndpi_flow_free does the same thing with the deallocator - you can either use the vanilla free from the standard library, or pass a custom deallocator:

set_ndpi_flow_free( free );

or

void my_free( void *ptr )
{
  ...
}
...
set_ndpi_flow_free( my_free );
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Wow, thanks John, this is incredibly detailed and informative. You make perfect sense. So I think for my purposes, I don't need set_ndpi_flow_free() but the simpler ndpi_flow_malloc() function, which I'm guessing the authors intended as the default selection. Thank you! – Pete Sep 18 '20 at 19:54