Skip to content

Commit a37492c

Browse files
FaramosCZclaude
authored andcommitted
CONC-813, CONC-814 Fix UBSan errors
sint4korr (non-x86 path): the expression `(int16)(A)[3] << 24` causes signed integer overflow when byte value >= 128, since 128<<24 exceeds INT32_MAX. Redefine as `(int32) uint4korr(A)` to compute in unsigned arithmetic, matching the server (my_byteorder.h:137-140). The next line sint8korr already uses this same pattern: `(longlong) uint8korr(A)`. convert_from_long (MYSQL_TYPE_DOUBLE, MYSQL_TYPE_FLOAT): casting double/float back to ulonglong/longlong for truncation detection is undefined when the float value is outside the representable integer range. For example, `(double)ULONGLONG_MAX` rounds up to 2^64 in IEEE 754 (not exactly representable with 53-bit mantissa), so `(ulonglong)dbl` overflows. Similarly for LONGLONG_MAX. Add range checks before the cast using `>=` for upper bounds (since the double rounds up past the integer max) and `<` for LONGLONG_MIN (exactly representable as -2^63). Out-of-range values set the truncation error flag directly, short-circuiting the dangerous cast via `||` evaluation. This matches the server pattern in sql/field.cc and sql/sql_select.cc (double_to_ulonglong macro). Co-Authored-By: Claude AI <noreply@anthropic.com>
1 parent c44bc3b commit a37492c

2 files changed

Lines changed: 23 additions & 10 deletions

File tree

include/ma_global.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -838,10 +838,7 @@ do { doubleget_union _tmp; \
838838
(((uint32) (uchar) (A)[2]) << 16) |\
839839
(((uint32) (uchar) (A)[1]) << 8) | \
840840
((uint32) (uchar) (A)[0])))
841-
#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\
842-
(((int32) ((uchar) (A)[1]) << 8)) +\
843-
(((int32) ((uchar) (A)[2]) << 16)) +\
844-
(((int32) ((int16) (A)[3]) << 24)))
841+
#define sint4korr(A) (int32) uint4korr(A)
845842
#define sint8korr(A) (longlong) uint8korr(A)
846843
#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\
847844
((uint16) ((uchar) (A)[1]) << 8))

libmariadb/ma_stmt_codec.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,16 @@ static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, lon
633633
dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val;
634634
doublestore(r_param->buffer, dbl);
635635

636-
*r_param->error = (dbl != ceil(dbl)) ||
637-
(is_unsigned ? (ulonglong )dbl != (ulonglong)val :
638-
(longlong)dbl != (longlong)val);
636+
if (dbl != ceil(dbl))
637+
*r_param->error= 1;
638+
else if (is_unsigned)
639+
*r_param->error= dbl < 0 ||
640+
dbl >= (double)ULONGLONG_MAX ||
641+
(ulonglong)dbl != (ulonglong)val;
642+
else
643+
*r_param->error= dbl < (double)LONGLONG_MIN ||
644+
dbl >= (double)LONGLONG_MAX ||
645+
(longlong)dbl != (longlong)val;
639646

640647
r_param->buffer_length= 8;
641648
break;
@@ -645,9 +652,18 @@ static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, lon
645652
volatile float fval;
646653
fval= is_unsigned ? (float)(ulonglong)(val) : (float)val;
647654
floatstore((uchar *)r_param->buffer, fval);
648-
*r_param->error= (fval != ceilf(fval)) ||
649-
(is_unsigned ? (ulonglong)fval != (ulonglong)val :
650-
(longlong)fval != val);
655+
656+
if (fval != ceilf(fval))
657+
*r_param->error= 1;
658+
else if (is_unsigned)
659+
*r_param->error= fval < 0 ||
660+
fval >= (float)ULONGLONG_MAX ||
661+
(ulonglong)fval != (ulonglong)val;
662+
else
663+
*r_param->error= fval < (float)LONGLONG_MIN ||
664+
fval >= (float)LONGLONG_MAX ||
665+
(longlong)fval != val;
666+
651667
r_param->buffer_length= 4;
652668
}
653669
break;

0 commit comments

Comments
 (0)