MDEV-20917 InnoDB is passing NULL to nonnull function parameters

mem_heap_dup(): Avoid mem_heap_alloc() and memcpy() of data=NULL, len=0.

trx_undo_report_insert_virtual(), trx_undo_page_report_insert(),
trx_undo_page_report_modify(): Avoid memcpy(ptr, NULL, 0).

dfield_data_is_binary_equal(): Correctly handle data=NULL, len=0.

This clean-up was motivated by WITH_UBSAN, and no bug related to this
was observed in the wild. It should be noted that undefined behaviour
such as memcpy(ptr, NULL, 0) could allow compilers to perform unsafe
optimizations, like it was the case in
commit fc168c3a5e (MDEV-15587).
This commit is contained in:
Marko Mäkelä 2019-10-29 17:11:34 +02:00
parent 2d82ae5ba3
commit 814534745b
5 changed files with 42 additions and 45 deletions

View file

@ -168,7 +168,7 @@ dfield_data_is_binary_equal(
const dfield_t* field, /*!< in: field */
ulint len, /*!< in: data length or UNIV_SQL_NULL */
const byte* data) /*!< in: data */
MY_ATTRIBUTE((nonnull, warn_unused_result));
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/*********************************************************************//**
Gets info bits in a data tuple.

View file

@ -223,7 +223,7 @@ dfield_data_is_binary_equal(
const byte* data) /*!< in: data */
{
return(len == dfield_get_len(field)
&& (len == UNIV_SQL_NULL
&& (!len || len == UNIV_SQL_NULL
|| !memcmp(dfield_get_data(field), data, len)));
}

View file

@ -228,7 +228,22 @@ mem_strdupl(
const char* str, /*!< in: string to be copied */
ulint len); /*!< in: length of str, in bytes */
/** Duplicates a NUL-terminated string, allocated from a memory heap.
/** Duplicate a block of data, allocated from a memory heap.
@param[in] heap memory heap where string is allocated
@param[in] data block of data to be copied
@param[in] len length of data, in bytes
@return own: a copy of data */
inline
void*
mem_heap_dup(mem_heap_t* heap, const void* data, size_t len)
{
ut_ad(data || !len);
return UNIV_LIKELY(data != NULL)
? memcpy(mem_heap_alloc(heap, len), data, len)
: NULL;
}
/** Duplicate a NUL-terminated string, allocated from a memory heap.
@param[in] heap memory heap where string is allocated
@param[in] str string to be copied
@return own: a copy of the string */
@ -259,16 +274,6 @@ mem_heap_strcat(
const char* s1, /*!< in: string 1 */
const char* s2); /*!< in: string 2 */
/**********************************************************************//**
Duplicate a block of data, allocated from a memory heap.
@return own: a copy of the data */
void*
mem_heap_dup(
/*=========*/
mem_heap_t* heap, /*!< in: memory heap where copy is allocated */
const void* data, /*!< in: data to be copied */
ulint len); /*!< in: length of data, in bytes */
/****************************************************************//**
A simple sprintf replacement that dynamically allocates the space for the
formatted string from the given heap. This supports a very limited set of

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2018, MariaDB Corporation.
Copyright (c) 2017, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -41,19 +41,6 @@ mem_heap_strdup(
return(static_cast<char*>(mem_heap_dup(heap, str, strlen(str) + 1)));
}
/**********************************************************************//**
Duplicate a block of data, allocated from a memory heap.
@return own: a copy of the data */
void*
mem_heap_dup(
/*=========*/
mem_heap_t* heap, /*!< in: memory heap where copy is allocated */
const void* data, /*!< in: data to be copied */
ulint len) /*!< in: length of data, in bytes */
{
return(memcpy(mem_heap_alloc(heap, len), data, len));
}
/**********************************************************************//**
Concatenate two strings and return the result, using a memory heap.
@return own: the result */

View file

@ -412,9 +412,15 @@ trx_undo_report_insert_virtual(
const dfield_t* vfield = dtuple_get_nth_v_field(
row, col->v_pos);
ulint flen = vfield->len;
switch (ulint flen = vfield->len) {
case 0: case UNIV_SQL_NULL:
if (trx_undo_left(undo_page, *ptr) < 5) {
return(false);
}
if (flen != UNIV_SQL_NULL) {
*ptr += mach_write_compressed(*ptr, flen);
break;
default:
ulint max_len
= dict_max_v_field_len_store_undo(
table, col_no);
@ -429,15 +435,8 @@ trx_undo_report_insert_virtual(
}
*ptr += mach_write_compressed(*ptr, flen);
ut_memcpy(*ptr, vfield->data, flen);
memcpy(*ptr, vfield->data, flen);
*ptr += flen;
} else {
if (trx_undo_left(undo_page, *ptr) < 5) {
return(false);
}
*ptr += mach_write_compressed(*ptr, flen);
}
}
}
@ -506,13 +505,16 @@ trx_undo_page_report_insert(
ptr += mach_write_compressed(ptr, flen);
if (flen != UNIV_SQL_NULL) {
switch (flen) {
case 0: case UNIV_SQL_NULL:
break;
default:
if (trx_undo_left(undo_page, ptr) < flen) {
return(0);
}
ut_memcpy(ptr, dfield_get_data(field), flen);
memcpy(ptr, dfield_get_data(field), flen);
ptr += flen;
}
}
@ -981,7 +983,7 @@ trx_undo_page_report_modify(
return(0);
}
ut_memcpy(ptr, field, flen);
memcpy(ptr, field, flen);
ptr += flen;
}
}
@ -1123,7 +1125,7 @@ trx_undo_page_report_modify(
return(0);
}
ut_memcpy(ptr, field, flen);
memcpy(ptr, field, flen);
ptr += flen;
}
@ -1149,7 +1151,7 @@ trx_undo_page_report_modify(
return(0);
}
ut_memcpy(ptr, field, flen);
memcpy(ptr, field, flen);
ptr += flen;
}
}
@ -1305,7 +1307,7 @@ trx_undo_page_report_modify(
return(0);
}
ut_memcpy(ptr, field, flen);
memcpy(ptr, field, flen);
ptr += flen;
}
@ -1391,14 +1393,17 @@ already_logged:
ptr += mach_write_compressed(ptr, flen);
if (flen != UNIV_SQL_NULL) {
switch (flen) {
case 0: case UNIV_SQL_NULL:
break;
default:
if (trx_undo_left(undo_page, ptr)
< flen) {
return(0);
}
ut_memcpy(ptr, field, flen);
memcpy(ptr, field, flen);
ptr += flen;
}
}