1/*****************************************************************************
2
3Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free Software
7Foundation; version 2 of the License.
8
9This program is distributed in the hope that it will be useful, but WITHOUT
10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License along with
14this program; if not, write to the Free Software Foundation, Inc.,
1551 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16
17*****************************************************************************/
18
19/******************************************************************//**
20@file mach/mach0data.cc
21Utilities for converting data from the database file
22to the machine format.
23
24Created 11/28/1995 Heikki Tuuri
25***********************************************************************/
26
27#include "mach0data.h"
28
29/** Read a 32-bit integer in a compressed form.
30@param[in,out] ptr pointer to memory where to read;
31advanced by the number of bytes consumed, or set NULL if out of space
32@param[in] end_ptr end of the buffer
33@return unsigned value */
34ib_uint32_t
35mach_parse_compressed(
36 const byte** ptr,
37 const byte* end_ptr)
38{
39 ulint val;
40
41 if (*ptr >= end_ptr) {
42 *ptr = NULL;
43 return(0);
44 }
45
46 val = mach_read_from_1(*ptr);
47
48 if (val < 0x80) {
49 /* 0nnnnnnn (7 bits) */
50 ++*ptr;
51 return(static_cast<ib_uint32_t>(val));
52 }
53
54 /* Workaround GCC bug
55 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673:
56 the compiler moves mach_read_from_4 right to the beginning of the
57 function, causing and out-of-bounds read if we are reading a short
58 integer close to the end of buffer. */
59#if defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__clang__)
60#define DEPLOY_FENCE
61#endif
62
63#ifdef DEPLOY_FENCE
64 __atomic_thread_fence(__ATOMIC_ACQUIRE);
65#endif
66
67 if (val < 0xC0) {
68 /* 10nnnnnn nnnnnnnn (14 bits) */
69 if (end_ptr >= *ptr + 2) {
70 val = mach_read_from_2(*ptr) & 0x3FFF;
71 ut_ad(val > 0x7F);
72 *ptr += 2;
73 return(static_cast<ib_uint32_t>(val));
74 }
75 *ptr = NULL;
76 return(0);
77 }
78
79#ifdef DEPLOY_FENCE
80 __atomic_thread_fence(__ATOMIC_ACQUIRE);
81#endif
82
83 if (val < 0xE0) {
84 /* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
85 if (end_ptr >= *ptr + 3) {
86 val = mach_read_from_3(*ptr) & 0x1FFFFF;
87 ut_ad(val > 0x3FFF);
88 *ptr += 3;
89 return(static_cast<ib_uint32_t>(val));
90 }
91 *ptr = NULL;
92 return(0);
93 }
94
95#ifdef DEPLOY_FENCE
96 __atomic_thread_fence(__ATOMIC_ACQUIRE);
97#endif
98
99 if (val < 0xF0) {
100 /* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
101 if (end_ptr >= *ptr + 4) {
102 val = mach_read_from_4(*ptr) & 0xFFFFFFF;
103 ut_ad(val > 0x1FFFFF);
104 *ptr += 4;
105 return(static_cast<ib_uint32_t>(val));
106 }
107 *ptr = NULL;
108 return(0);
109 }
110
111#ifdef DEPLOY_FENCE
112 __atomic_thread_fence(__ATOMIC_ACQUIRE);
113#endif
114
115#undef DEPLOY_FENCE
116
117 ut_ad(val == 0xF0);
118
119 /* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
120 if (end_ptr >= *ptr + 5) {
121 val = mach_read_from_4(*ptr + 1);
122 ut_ad(val > 0xFFFFFFF);
123 *ptr += 5;
124 return(static_cast<ib_uint32_t>(val));
125 }
126
127 *ptr = NULL;
128 return(0);
129}
130