Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/PrimitiveConversions.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/**
8
 * Conversions from jsval to primitive values
9
 */
10
11
#ifndef mozilla_dom_PrimitiveConversions_h
12
#define mozilla_dom_PrimitiveConversions_h
13
14
#include <limits>
15
#include <math.h>
16
#include <stdint.h>
17
18
#include "jsapi.h"
19
#include "js/Conversions.h"
20
#include "mozilla/Assertions.h"
21
#include "mozilla/ErrorResult.h"
22
#include "mozilla/FloatingPoint.h"
23
24
namespace mozilla {
25
namespace dom {
26
27
template<typename T>
28
struct TypeName {
29
};
30
31
template<>
32
struct TypeName<int8_t> {
33
0
  static const char* value() {
34
0
    return "byte";
35
0
  }
36
};
37
template<>
38
struct TypeName<uint8_t> {
39
0
  static const char* value() {
40
0
    return "octet";
41
0
  }
42
};
43
template<>
44
struct TypeName<int16_t> {
45
0
  static const char* value() {
46
0
    return "short";
47
0
  }
48
};
49
template<>
50
struct TypeName<uint16_t> {
51
0
  static const char* value() {
52
0
    return "unsigned short";
53
0
  }
54
};
55
template<>
56
struct TypeName<int32_t> {
57
0
  static const char* value() {
58
0
    return "long";
59
0
  }
60
};
61
template<>
62
struct TypeName<uint32_t> {
63
0
  static const char* value() {
64
0
    return "unsigned long";
65
0
  }
66
};
67
template<>
68
struct TypeName<int64_t> {
69
0
  static const char* value() {
70
0
    return "long long";
71
0
  }
72
};
73
template<>
74
struct TypeName<uint64_t> {
75
0
  static const char* value() {
76
0
    return "unsigned long long";
77
0
  }
78
};
79
80
81
enum ConversionBehavior {
82
  eDefault,
83
  eEnforceRange,
84
  eClamp
85
};
86
87
template<typename T, ConversionBehavior B>
88
struct PrimitiveConversionTraits {
89
};
90
91
template<typename T>
92
struct DisallowedConversion {
93
  typedef int jstype;
94
  typedef int intermediateType;
95
96
private:
97
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
98
                               jstype* retval) {
99
    MOZ_CRASH("This should never be instantiated!");
100
  }
101
};
102
103
struct PrimitiveConversionTraits_smallInt {
104
  // The output of JS::ToInt32 is determined as follows:
105
  //   1) The value is converted to a double
106
  //   2) Anything that's not a finite double returns 0
107
  //   3) The double is rounded towards zero to the nearest integer
108
  //   4) The resulting integer is reduced mod 2^32.  The output of this
109
  //      operation is an integer in the range [0, 2^32).
110
  //   5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
111
  //
112
  // The result of all this is a number in the range [-2^31, 2^31)
113
  //
114
  // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
115
  // are defined in the same way, except that step 4 uses reduction mod
116
  // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
117
  // is only done for the signed types.
118
  //
119
  // C/C++ define integer conversion semantics to unsigned types as taking
120
  // your input integer mod (1 + largest value representable in the
121
  // unsigned type).  Since 2^32 is zero mod 2^8, 2^16, and 2^32,
122
  // converting to the unsigned int of the relevant width will correctly
123
  // perform step 4; in particular, the 2^32 possibly subtracted in step 5
124
  // will become 0.
125
  //
126
  // Once we have step 4 done, we're just going to assume 2s-complement
127
  // representation and cast directly to the type we really want.
128
  //
129
  // So we can cast directly for all unsigned types and for int32_t; for
130
  // the smaller-width signed types we need to cast through the
131
  // corresponding unsigned type.
132
  typedef int32_t jstype;
133
  typedef int32_t intermediateType;
134
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
135
0
                               jstype* retval) {
136
0
    return JS::ToInt32(cx, v, retval);
137
0
  }
138
};
139
template<>
140
struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt {
141
  typedef uint8_t intermediateType;
142
};
143
template<>
144
struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt {
145
};
146
template<>
147
struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt {
148
  typedef uint16_t intermediateType;
149
};
150
template<>
151
struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt {
152
};
153
template<>
154
struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt {
155
};
156
template<>
157
struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt {
158
};
159
160
template<>
161
struct PrimitiveConversionTraits<int64_t, eDefault> {
162
  typedef int64_t jstype;
163
  typedef int64_t intermediateType;
164
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
165
0
                               jstype* retval) {
166
0
    return JS::ToInt64(cx, v, retval);
167
0
  }
168
};
169
170
template<>
171
struct PrimitiveConversionTraits<uint64_t, eDefault> {
172
  typedef uint64_t jstype;
173
  typedef uint64_t intermediateType;
174
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
175
0
                               jstype* retval) {
176
0
    return JS::ToUint64(cx, v, retval);
177
0
  }
178
};
179
180
template<typename T>
181
struct PrimitiveConversionTraits_Limits {
182
0
  static inline T min() {
183
0
    return std::numeric_limits<T>::min();
184
0
  }
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned char>::min()
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned int>::min()
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned short>::min()
185
0
  static inline T max() {
186
0
    return std::numeric_limits<T>::max();
187
0
  }
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned char>::max()
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned int>::max()
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_Limits<unsigned short>::max()
188
};
189
190
template<>
191
struct PrimitiveConversionTraits_Limits<int64_t> {
192
0
  static inline int64_t min() {
193
0
    return -(1LL << 53) + 1;
194
0
  }
195
0
  static inline int64_t max() {
196
0
    return (1LL << 53) - 1;
197
0
  }
198
};
199
200
template<>
201
struct PrimitiveConversionTraits_Limits<uint64_t> {
202
0
  static inline uint64_t min() {
203
0
    return 0;
204
0
  }
205
0
  static inline uint64_t max() {
206
0
    return (1LL << 53) - 1;
207
0
  }
208
};
209
210
template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)>
211
struct PrimitiveConversionTraits_ToCheckedIntHelper {
212
  typedef T jstype;
213
  typedef T intermediateType;
214
215
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
216
0
                               jstype* retval) {
217
0
    double intermediate;
218
0
    if (!JS::ToNumber(cx, v, &intermediate)) {
219
0
      return false;
220
0
    }
221
0
222
0
    return Enforce(cx, intermediate, retval);
223
0
  }
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<long, &(bool mozilla::dom::PrimitiveConversionTraits_Clamp<long>(JSContext*, double const&, long*))>::converter(JSContext*, JS::Handle<JS::Value>, long*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned long, &(bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned long>(JSContext*, double const&, unsigned long*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned long*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned char, &(bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned char>(JSContext*, double const&, unsigned char*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned char*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned int, &(bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned int>(JSContext*, double const&, unsigned int*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned int*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned short, &(bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned short>(JSContext*, double const&, unsigned short*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned short*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned short, &(bool mozilla::dom::PrimitiveConversionTraits_Clamp<unsigned short>(JSContext*, double const&, unsigned short*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned short*)
Unexecuted instantiation: mozilla::dom::PrimitiveConversionTraits_ToCheckedIntHelper<unsigned int, &(bool mozilla::dom::PrimitiveConversionTraits_Clamp<unsigned int>(JSContext*, double const&, unsigned int*))>::converter(JSContext*, JS::Handle<JS::Value>, unsigned int*)
224
};
225
226
template<typename T>
227
inline bool
228
PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval)
229
0
{
230
0
  static_assert(std::numeric_limits<T>::is_integer,
231
0
                "This can only be applied to integers!");
232
0
233
0
  if (!mozilla::IsFinite(d)) {
234
0
    return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value());
235
0
  }
236
0
237
0
  bool neg = (d < 0);
238
0
  double rounded = floor(neg ? -d : d);
239
0
  rounded = neg ? -rounded : rounded;
240
0
  if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
241
0
      rounded > PrimitiveConversionTraits_Limits<T>::max()) {
242
0
    return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value());
243
0
  }
244
0
245
0
  *retval = static_cast<T>(rounded);
246
0
  return true;
247
0
}
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned long>(JSContext*, double const&, unsigned long*)
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned char>(JSContext*, double const&, unsigned char*)
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned int>(JSContext*, double const&, unsigned int*)
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_EnforceRange<unsigned short>(JSContext*, double const&, unsigned short*)
248
249
template<typename T>
250
struct PrimitiveConversionTraits<T, eEnforceRange> :
251
  public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > {
252
};
253
254
template<typename T>
255
inline bool
256
PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval)
257
0
{
258
0
  static_assert(std::numeric_limits<T>::is_integer,
259
0
                "This can only be applied to integers!");
260
0
261
0
  if (mozilla::IsNaN(d)) {
262
0
    *retval = 0;
263
0
    return true;
264
0
  }
265
0
  if (d >= PrimitiveConversionTraits_Limits<T>::max()) {
266
0
    *retval = PrimitiveConversionTraits_Limits<T>::max();
267
0
    return true;
268
0
  }
269
0
  if (d <= PrimitiveConversionTraits_Limits<T>::min()) {
270
0
    *retval = PrimitiveConversionTraits_Limits<T>::min();
271
0
    return true;
272
0
  }
273
0
274
0
  MOZ_ASSERT(mozilla::IsFinite(d));
275
0
276
0
  // Banker's rounding (round ties towards even).
277
0
  // We move away from 0 by 0.5f and then truncate.  That gets us the right
278
0
  // answer for any starting value except plus or minus N.5.  With a starting
279
0
  // value of that form, we now have plus or minus N+1.  If N is odd, this is
280
0
  // the correct result.  If N is even, plus or minus N is the correct result.
281
0
  double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
282
0
283
0
  T truncated = static_cast<T>(toTruncate);
284
0
285
0
  if (truncated == toTruncate) {
286
0
    /*
287
0
     * It was a tie (since moving away from 0 by 0.5 gave us the exact integer
288
0
     * we want). Since we rounded away from 0, we either already have an even
289
0
     * number or we have an odd number but the number we want is one closer to
290
0
     * 0. So just unconditionally masking out the ones bit should do the trick
291
0
     * to get us the value we want.
292
0
     */
293
0
    truncated &= ~1;
294
0
  }
295
0
296
0
  *retval = truncated;
297
0
  return true;
298
0
}
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_Clamp<long>(JSContext*, double const&, long*)
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_Clamp<unsigned short>(JSContext*, double const&, unsigned short*)
Unexecuted instantiation: bool mozilla::dom::PrimitiveConversionTraits_Clamp<unsigned int>(JSContext*, double const&, unsigned int*)
299
300
template<typename T>
301
struct PrimitiveConversionTraits<T, eClamp> :
302
  public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > {
303
};
304
305
306
template<ConversionBehavior B>
307
struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {};
308
309
template<>
310
struct PrimitiveConversionTraits<bool, eDefault> {
311
  typedef bool jstype;
312
  typedef bool intermediateType;
313
  static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v,
314
0
                               jstype* retval) {
315
0
    *retval = JS::ToBoolean(v);
316
0
    return true;
317
0
  }
318
};
319
320
321
template<ConversionBehavior B>
322
struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {};
323
324
template<ConversionBehavior B>
325
struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {};
326
327
struct PrimitiveConversionTraits_float {
328
  typedef double jstype;
329
  typedef double intermediateType;
330
  static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
331
0
                               jstype* retval) {
332
0
    return JS::ToNumber(cx, v, retval);
333
0
  }
334
};
335
336
template<>
337
struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float {
338
};
339
template<>
340
struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float {
341
};
342
343
344
template<typename T, ConversionBehavior B>
345
bool ValueToPrimitive(JSContext* cx, JS::Handle<JS::Value> v, T* retval)
346
0
{
347
0
  typename PrimitiveConversionTraits<T, B>::jstype t;
348
0
  if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
349
0
    return false;
350
0
351
0
  *retval = static_cast<T>(
352
0
    static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
353
0
  return true;
354
0
}
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<signed char, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, signed char*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<short, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, short*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<int, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, int*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<long, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, long*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned char, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, unsigned char*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned short, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, unsigned short*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned int, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, unsigned int*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned long, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, unsigned long*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<float, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, float*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<double, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, double*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<bool, (mozilla::dom::ConversionBehavior)0>(JSContext*, JS::Handle<JS::Value>, bool*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<long, (mozilla::dom::ConversionBehavior)2>(JSContext*, JS::Handle<JS::Value>, long*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned long, (mozilla::dom::ConversionBehavior)1>(JSContext*, JS::Handle<JS::Value>, unsigned long*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned char, (mozilla::dom::ConversionBehavior)1>(JSContext*, JS::Handle<JS::Value>, unsigned char*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned int, (mozilla::dom::ConversionBehavior)1>(JSContext*, JS::Handle<JS::Value>, unsigned int*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned short, (mozilla::dom::ConversionBehavior)1>(JSContext*, JS::Handle<JS::Value>, unsigned short*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned short, (mozilla::dom::ConversionBehavior)2>(JSContext*, JS::Handle<JS::Value>, unsigned short*)
Unexecuted instantiation: bool mozilla::dom::ValueToPrimitive<unsigned int, (mozilla::dom::ConversionBehavior)2>(JSContext*, JS::Handle<JS::Value>, unsigned int*)
355
356
} // namespace dom
357
} // namespace mozilla
358
359
#endif /* mozilla_dom_PrimitiveConversions_h */