2
0

NULL out free'ed references.

This commit is contained in:
Maarten Billemont
2017-08-23 00:01:23 -04:00
parent 0a42579d9e
commit a8949ca07e
12 changed files with 171 additions and 172 deletions

View File

@@ -18,7 +18,6 @@
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
@@ -71,7 +70,7 @@ static MPMasterKey mpw_masterKey_v0(
// Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
mpw_free( &masterKeySalt, masterKeySaltSize );
if (!masterKey) {
err( "Could not allocate master key: %s\n", strerror( errno ) );
return NULL;
@@ -104,9 +103,8 @@ static MPSiteKey mpw_siteKey_v0(
mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
}
if (!siteSalt || !siteSaltSize) {
if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) );
mpw_free( siteSalt, siteSaltSize );
return NULL;
}
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
@@ -114,7 +112,7 @@ static MPSiteKey mpw_siteKey_v0(
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) {
err( "Could not derive site key: %s\n", strerror( errno ) );
return NULL;
@@ -163,19 +161,19 @@ static const char *mpw_sitePasswordFromCrypt_v0(
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText );
if ((int)bufSize < 0) {
err( "Base64 decoding error." );
mpw_free( cipherBuf, mpw_base64_decode_max( cipherText ) );
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
return NULL;
}
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
// Decrypt
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
mpw_free( &cipherBuf, bufSize );
const char *plainText = strndup( (char *)plainBytes, bufSize );
mpw_free( plainBytes, bufSize );
mpw_free( &plainBytes, bufSize );
if (!plainText)
err( "AES decryption error: %s\n", strerror( errno ) );
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
mpw_free( cipherBuf, bufSize );
return plainText;
}
@@ -206,15 +204,16 @@ static const char *mpw_sitePasswordFromDerive_v0(
// Base64-encode
size_t b64Max = mpw_base64_encode_max( keySize );
char *sitePassword = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( sitePassword, resultKey, keySize ) < 0) {
char *b64Key = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( b64Key, resultKey, keySize ) < 0) {
err( "Base64 encoding error." );
mpw_free_string( sitePassword );
sitePassword = NULL;
mpw_free_string( &b64Key );
}
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( sitePassword, strlen( sitePassword ) ) );
else
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) );
mpw_free( &resultKey, keySize );
return sitePassword;
return b64Key;
}
default:
err( "Unsupported derived password type: %d\n", resultType );
@@ -239,11 +238,11 @@ static const char *mpw_siteState_v0(
char *cipherText = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( cipherText, cipherBuf, bufSize ) < 0) {
err( "Base64 encoding error." );
mpw_free_string( cipherText );
cipherText = NULL;
mpw_free_string( &cipherText );
}
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
mpw_free( cipherBuf, bufSize );
else
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
mpw_free( &cipherBuf, bufSize );
return cipherText;
}

View File

@@ -69,9 +69,8 @@ static MPSiteKey mpw_siteKey_v2(
mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
}
if (!siteSalt || !siteSaltSize) {
if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) );
mpw_free( siteSalt, siteSaltSize );
return NULL;
}
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
@@ -79,7 +78,7 @@ static MPSiteKey mpw_siteKey_v2(
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) {
err( "Could not allocate site key: %s\n", strerror( errno ) );
return NULL;

View File

@@ -64,7 +64,7 @@ static MPMasterKey mpw_masterKey_v3(
// Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
mpw_free( &masterKeySalt, masterKeySaltSize );
if (!masterKey) {
err( "Could not allocate master key: %s\n", strerror( errno ) );
return NULL;

View File

@@ -100,10 +100,9 @@ bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyA
const char *fullName, const char *masterPassword) {
if (*masterKeyAlgorithm != targetKeyAlgorithm) {
mpw_free( *masterKey, MPMasterKeySize );
mpw_free( masterKey, MPMasterKeySize );
*masterKeyAlgorithm = targetKeyAlgorithm;
*masterKey = mpw_masterKey(
fullName, masterPassword, *masterKeyAlgorithm );
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
if (!*masterKey) {
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm );
return false;

View File

@@ -94,42 +94,39 @@ MPMarshalledQuestion *mpw_marshal_question(
}
bool mpw_marshal_info_free(
MPMarshallInfo *info) {
MPMarshallInfo **info) {
if (!info)
if (!info || !*info)
return true;
bool success = true;
success &= mpw_free_string( info->fullName );
success &= mpw_free_string( info->keyID );
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
return success;
}
bool mpw_marshal_free(
MPMarshalledUser *user) {
MPMarshalledUser **user) {
if (!user)
return true;
bool success = true;
for (size_t s = 0; s < user->sites_count; ++s) {
MPMarshalledSite *site = &user->sites[s];
success &= mpw_free_string( site->name );
success &= mpw_free_string( site->content );
success &= mpw_free_string( site->loginContent );
success &= mpw_free_string( site->url );
success &= mpw_free_strings( &(*user)->fullName, &(*user)->masterPassword, NULL );
for (size_t s = 0; s < (*user)->sites_count; ++s) {
MPMarshalledSite *site = &(*user)->sites[s];
success &= mpw_free_strings( &site->name, &site->content, &site->loginContent, &site->url, NULL );
for (size_t q = 0; q < site->questions_count; ++q) {
MPMarshalledQuestion *question = &site->questions[q];
success &= mpw_free_string( question->keyword );
success &= mpw_free_string( question->content );
success &= mpw_free_strings( &question->keyword, &question->content, NULL );
}
success &= mpw_free( site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
success &= mpw_free( &site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
}
success &= mpw_free( user->sites, sizeof( MPMarshalledSite ) * user->sites_count );
success &= mpw_free_string( user->fullName );
success &= mpw_free_string( user->masterPassword );
success &= mpw_free( &(*user)->sites, sizeof( MPMarshalledSite ) * (*user)->sites_count );
success &= mpw_free( user, sizeof( MPMarshalledUser ) );
return success;
@@ -210,10 +207,9 @@ static bool mpw_marshall_write_flat(
mpw_string_pushf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n",
dateString, (long)site->uses, (long)site->type, (long)site->algorithm, (long)site->counter,
loginContent?: "", site->name, content?: "" );
mpw_free_string( content );
mpw_free_string( loginContent );
mpw_free_strings( &content, &loginContent, NULL );
}
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return true;
@@ -336,11 +332,11 @@ static bool mpw_marshall_write_json(
if (site->url)
json_object_object_add( json_site_mpw, "url", json_object_new_string( site->url ) );
mpw_free_string( content );
mpw_free_strings( &content, &loginContent );
}
mpw_string_pushf( out, "%s\n", json_object_to_json_string_ext( json_file, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED ) );
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
json_object_put( json_file );
*error = (MPMarshallError){ .type = MPMarshallSuccess };
@@ -405,8 +401,7 @@ static void mpw_marshall_read_flat_info(
if (strcmp( headerName, "Date" ) == 0)
info->date = mpw_mktime( headerValue );
mpw_free_string( headerName );
mpw_free_string( headerValue );
mpw_free_strings( &headerName, &headerValue, NULL );
continue;
}
}
@@ -488,8 +483,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (strcmp( headerName, "Passwords" ) == 0)
importRedacted = strcmp( headerValue, "VISIBLE" ) != 0;
mpw_free_string( headerName );
mpw_free_string( headerValue );
mpw_free_strings( &headerName, &headerValue, NULL );
continue;
}
if (!headerEnded)
@@ -531,7 +525,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (typeAndVersion) {
str_type = strdup( strtok( typeAndVersion, ":" ) );
str_algorithm = strdup( strtok( NULL, "" ) );
mpw_free_string( typeAndVersion );
mpw_free_string( &typeAndVersion );
}
str_counter = strdup( "1" );
siteLoginName = NULL;
@@ -547,7 +541,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
str_algorithm = strdup( strtok( NULL, ":" ) );
str_counter = strdup( strtok( NULL, "" ) );
mpw_free_string( typeAndVersionAndCounter );
mpw_free_string( &typeAndVersionAndCounter );
}
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
@@ -606,6 +600,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
dbg( "site->content: %p\n", (void *)site->content );
}
else {
// Redacted
@@ -613,6 +608,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
site->content = strdup( siteContent );
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName );
dbg( "site->content: %p\n", (void *)site->content );
}
}
else {
@@ -623,18 +619,11 @@ static MPMarshalledUser *mpw_marshall_read_flat(
return NULL;
}
mpw_free_string( str_lastUsed );
mpw_free_string( str_uses );
mpw_free_string( str_type );
mpw_free_string( str_algorithm );
mpw_free_string( str_counter );
mpw_free_string( siteLoginName );
mpw_free_string( siteName );
mpw_free_string( siteContent );
mpw_free_strings( &str_lastUsed, &str_uses, &str_type, &str_algorithm, &str_counter, NULL );
mpw_free_strings( &siteLoginName, &siteName, &siteContent, NULL );
}
mpw_free_string( fullName );
mpw_free_string( keyID );
mpw_free( masterKey, MPMasterKeySize );
mpw_free_strings( &fullName, &keyID, NULL );
mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return user;
@@ -796,6 +785,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
dbg( "site->content: %p\n", (void *)site->content );
}
else {
// Redacted
@@ -803,6 +793,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
site->content = strdup( siteContent );
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName );
dbg( "site->content: %p\n", (void *)site->content );
}
json_object_iter json_site_question;

View File

@@ -130,9 +130,9 @@ MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledSite *site, const char *keyword);
/** Free the given user object and all associated data. */
bool mpw_marshal_info_free(
MPMarshallInfo *info);
MPMarshallInfo **info);
bool mpw_marshal_free(
MPMarshalledUser *user);
MPMarshalledUser **user);
//// Format.

View File

@@ -39,7 +39,7 @@
int mpw_verbosity = inf_level;
#endif
bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
bool mpw_push_buf(uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize) {
if (!buffer || !bufferSize || !pushBuffer || !pushSize)
return false;
@@ -49,9 +49,8 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
if (!mpw_realloc( buffer, bufferSize, pushSize )) {
// realloc failed, we can't push. Mark the buffer as broken.
mpw_free( *buffer, *bufferSize );
mpw_free( buffer, *bufferSize );
*bufferSize = (size_t)ERR;
*buffer = NULL;
return false;
}
@@ -60,12 +59,12 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
return true;
}
bool mpw_push_string(uint8_t **const buffer, size_t *const bufferSize, const char *pushString) {
bool mpw_push_string(uint8_t **buffer, size_t *bufferSize, const char *pushString) {
return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
}
bool mpw_string_push(char **const string, const char *pushString) {
bool mpw_string_push(char **string, const char *pushString) {
if (!*string)
*string = calloc( 1, sizeof( char ) );
@@ -74,29 +73,29 @@ bool mpw_string_push(char **const string, const char *pushString) {
return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 );
}
bool mpw_string_pushf(char **const string, const char *pushFormat, ...) {
bool mpw_string_pushf(char **string, const char *pushFormat, ...) {
va_list args;
va_start( args, pushFormat );
char *pushString = NULL;
bool success = vasprintf( &pushString, pushFormat, args ) >= 0 && mpw_string_push( string, pushString );
va_end( args );
mpw_free_string( pushString );
mpw_free_string( &pushString );
return success;
}
bool mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
bool mpw_push_int(uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt) {
return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
}
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize) {
if (!buffer)
return false;
void *newBuffer = realloc( *buffer, (bufferSize? *bufferSize: 0) + deltaSize );
void *newBuffer = realloc( (void *)*buffer, (bufferSize? *bufferSize: 0) + deltaSize );
if (!newBuffer)
return false;
@@ -107,24 +106,31 @@ bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
return true;
}
bool mpw_free(const void *buffer, const size_t bufferSize) {
bool __mpw_free(const void **buffer, const size_t bufferSize) {
if (!buffer)
if (!buffer || !*buffer)
return false;
memset( (void *)buffer, 0, bufferSize );
free( (void *)buffer );
memset( (void *)*buffer, 0, bufferSize );
free( (void *)*buffer );
*buffer = NULL;
return true;
}
bool mpw_free_string(const char *strings, ...) {
bool __mpw_free_string(const char **string) {
return *string && __mpw_free( (const void **)string, strlen( *string ) );
}
bool __mpw_free_strings(const char **strings, ...) {
bool success = true;
va_list args;
va_start( args, strings );
const char *string = va_arg( args, const char * );
success &= string && mpw_free( string, strlen( string ) );
for (const char **string; (string = va_arg( args, const char ** ));)
success &= mpw_free_string( string );
va_end( args );
return success;
@@ -142,12 +148,12 @@ uint8_t const *mpw_kdf_scrypt(const size_t keySize, const char *secret, const ui
#if HAS_CPERCIVA
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
mpw_free( key, keySize );
mpw_free( &key, keySize );
return NULL;
}
#elif HAS_SODIUM
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) != 0) {
mpw_free( key, keySize );
mpw_free( &key, keySize );
return NULL;
}
#else
@@ -192,7 +198,7 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
memcpy( personalBuf, personal, strlen( personal ) );
if (crypto_generichash_blake2b_salt_personal( subkey, subkeySize, context, contextSize, key, keySize, saltBuf, personalBuf ) != 0) {
mpw_free( subkey, subkeySize );
mpw_free( &subkey, subkeySize );
return NULL;
}
#else
@@ -222,7 +228,7 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
crypto_auth_hmacsha256_update( &state, message, messageSize ) != 0 ||
crypto_auth_hmacsha256_final( &state, mac ) != 0) {
mpw_free( mac, crypto_auth_hmacsha256_BYTES );
mpw_free( &mac, crypto_auth_hmacsha256_BYTES );
return NULL;
}
#else
@@ -248,7 +254,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
if (encrypt) {
uint8_t *const cipherBuf = malloc( bufSize );
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
mpw_free( cipherBuf, bufSize );
mpw_free( &cipherBuf, bufSize );
return NULL;
}
return cipherBuf;
@@ -256,7 +262,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
else {
uint8_t *const plainBuf = malloc( bufSize );
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
mpw_free( plainBuf, bufSize );
mpw_free( &plainBuf, bufSize );
return NULL;
}
for (size_t c = 0; c < bufSize; ++c)
@@ -415,7 +421,7 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
resetString );
mpw_free( identiconSeed, 32 );
mpw_free( &identiconSeed, 32 );
free( colorString );
free( resetString );
return identicon;

View File

@@ -106,18 +106,18 @@ extern int mpw_verbosity;
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
bool mpw_push_buf(
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize);
uint8_t ** buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize);
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
bool mpw_push_string(
uint8_t **buffer, size_t *const bufferSize, const char *pushString);
uint8_t **buffer, size_t *bufferSize, const char *pushString);
/** Push a string onto another string. reallocs the target string and appends the source string. */
bool mpw_string_push(
char **const string, const char *pushString);
char **string, const char *pushString);
bool mpw_string_pushf(
char **const string, const char *pushFormat, ...);
char **string, const char *pushFormat, ...);
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
bool mpw_push_int(
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt);
/** Reallocate the given buffer from the given size by adding the delta size.
* On success, the buffer size pointer will be updated to the buffer's new size
* and the buffer pointer may be updated to a new memory address.
@@ -128,14 +128,23 @@ bool mpw_push_int(
* @return true if successful, false if reallocation failed.
*/
#define mpw_realloc(buffer, bufferSize, deltaSize) \
__mpw_realloc( (void **)buffer, bufferSize, deltaSize )
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize);
/** Free a buffer after zero'ing its contents. */
bool mpw_free(
const void *buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents. */
bool mpw_free_string(
const char *strings, ...);
({ typeof(buffer) _b = buffer; const void *__b = *_b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); })
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
#define mpw_free(buffer, bufferSize) \
({ typeof(buffer) _b = buffer; const void *__b = *_b; __mpw_free((const void **)_b, bufferSize); })
bool __mpw_free(
const void **buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents, then set the reference to NULL. */
#define mpw_free_string(string) \
({ typeof(string) _s = string; const char *__s = *_s; __mpw_free_string((const char **)_s); })
bool __mpw_free_string(
const char **string);
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
#define mpw_free_strings(strings, ...) \
({ typeof(strings) _s = strings; const char *__s = *_s; __mpw_free_strings((const char **)strings, __VA_ARGS__); })
bool __mpw_free_strings(
const char **strings, ...);
//// Cryptographic functions.