Skip to main content

Output buffers

Some functions require the caller to supply the output buffer. Other functions allocate memory and return the result in the new buffers, and the caller must free them.

Caller-supplied buffers

Generally, a function that requires a user-supplied buffer has three arguments of the following form:

ubyte *pResult,
ubyte4 bufferSize,
ubyte4 *pResultLen

The caller supplies the buffer and the buffer size. The function places the result into the buffer and returns the resulting length (the number of bytes placed into the buffer). The caller can pass in a NULL for the output buffer. The function returns ERR_BUFFER_TOO_SMALL, and sets *pResultLen to the required size. The caller then allocates a buffer big enough and calls again.

The function does no processing until it knows the output buffer is big enough. Thus, the second call must contain the same input as the first call.

It is possible the required size is greater than the actual size. That is, the first call returned ERR_BUFFER_TOO_SMALL and reported the required size to be some value n. The second call contained a buffer of size n bytes, and the function performed the operation and placed (n ‑ δ) bytes into the buffer. In other words, the actual data length is less than the required data length. That happens because sometimes a function does not know the exact length of the output until it processes the data. Therefore, it determines a maximum output length required, verifies the buffer is big enough, processes, then discovers the output was shorter than the maximum. For example, when decrypting a block cipher with padding, the function strips off the padding. But until decrypting, it does not know how much padding there is, so it does not perform decryption until it knows the buffer is big enough. Hence, it returns a required length big enough to handle any pad size.

Function-allocated buffers

If a function is going to allocate memory and return that buffer to the caller, it will typically have “Alloc” in the name. For example, see CRYPTO_deriveKeyAlloc in mocsym.h or PKCS10_buildCertRequestAlloc in certops.h. The output arguments will look like this.

ubyte **ppResult,
ubyte4 *pResultLen

Declare a variable to be of type ubyte *, initialize it to NULL, and pass its address. The function deposits at that address a pointer to a newly allocated buffer. It is the caller’s responsibility to free that memory using MOC_FREE.

For example:

ubyte4 resultLen;
ubyte *pResult = NULL;

...

status = FnctAlloc (args, ..., &pResult, &resultLen);
if (OK != status)
    goto exit;

...

exit:
    if (NULL != pResult)
        MOC_FREE ((void **)&pResult);