1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/*
23
24 Data generators for fuzzing test data in a reproducible way.
25
26*/
27
28#include "SDL_config.h"
29
30#include <limits.h>
31/* Visual Studio 2008 doesn't have stdint.h */
32#if defined(_MSC_VER) && _MSC_VER <= 1500
33#define UINT8_MAX _UI8_MAX
34#define UINT16_MAX _UI16_MAX
35#define UINT32_MAX _UI32_MAX
36#define INT64_MIN _I64_MIN
37#define INT64_MAX _I64_MAX
38#define UINT64_MAX _UI64_MAX
39#else
40#include <stdint.h>
41#endif
42#include <stdio.h>
43#include <stdlib.h>
44#include <float.h>
45
46#include "SDL_test.h"
47
48/**
49 * Counter for fuzzer invocations
50 */
51static int fuzzerInvocationCounter = 0;
52
53/**
54 * Context for shared random number generator
55 */
56static SDLTest_RandomContext rndContext;
57
58/*
59 * Note: doxygen documentation markup for functions is in the header file.
60 */
61
62void
63SDLTest_FuzzerInit(Uint64 execKey)
64{
65 Uint32 a = (execKey >> 32) & 0x00000000FFFFFFFF;
66 Uint32 b = execKey & 0x00000000FFFFFFFF;
67 SDL_memset((void *)&rndContext, 0, sizeof(SDLTest_RandomContext));
68 SDLTest_RandomInit(&rndContext, a, b);
69 fuzzerInvocationCounter = 0;
70}
71
72int
73SDLTest_GetFuzzerInvocationCount()
74{
75 return fuzzerInvocationCounter;
76}
77
78Uint8
79SDLTest_RandomUint8()
80{
81 fuzzerInvocationCounter++;
82
83 return (Uint8) SDLTest_RandomInt(&rndContext) & 0x000000FF;
84}
85
86Sint8
87SDLTest_RandomSint8()
88{
89 fuzzerInvocationCounter++;
90
91 return (Sint8) SDLTest_RandomInt(&rndContext) & 0x000000FF;
92}
93
94Uint16
95SDLTest_RandomUint16()
96{
97 fuzzerInvocationCounter++;
98
99 return (Uint16) SDLTest_RandomInt(&rndContext) & 0x0000FFFF;
100}
101
102Sint16
103SDLTest_RandomSint16()
104{
105 fuzzerInvocationCounter++;
106
107 return (Sint16) SDLTest_RandomInt(&rndContext) & 0x0000FFFF;
108}
109
110Sint32
111SDLTest_RandomSint32()
112{
113 fuzzerInvocationCounter++;
114
115 return (Sint32) SDLTest_RandomInt(&rndContext);
116}
117
118Uint32
119SDLTest_RandomUint32()
120{
121 fuzzerInvocationCounter++;
122
123 return (Uint32) SDLTest_RandomInt(&rndContext);
124}
125
126Uint64
127SDLTest_RandomUint64()
128{
129 union {
130 Uint64 v64;
131 Uint32 v32[2];
132 } value;
133 value.v64 = 0;
134
135 fuzzerInvocationCounter++;
136
137 value.v32[0] = SDLTest_RandomSint32();
138 value.v32[1] = SDLTest_RandomSint32();
139
140 return value.v64;
141}
142
143Sint64
144SDLTest_RandomSint64()
145{
146 union {
147 Uint64 v64;
148 Uint32 v32[2];
149 } value;
150 value.v64 = 0;
151
152 fuzzerInvocationCounter++;
153
154 value.v32[0] = SDLTest_RandomSint32();
155 value.v32[1] = SDLTest_RandomSint32();
156
157 return (Sint64)value.v64;
158}
159
160
161
162Sint32
163SDLTest_RandomIntegerInRange(Sint32 pMin, Sint32 pMax)
164{
165 Sint64 min = pMin;
166 Sint64 max = pMax;
167 Sint64 temp;
168 Sint64 number;
169
170 if(pMin > pMax) {
171 temp = min;
172 min = max;
173 max = temp;
174 } else if(pMin == pMax) {
175 return (Sint32)min;
176 }
177
178 number = SDLTest_RandomUint32();
179 /* invocation count increment in preceeding call */
180
181 return (Sint32)((number % ((max + 1) - min)) + min);
182}
183
184/* !
185 * Generates a unsigned boundary value between the given boundaries.
186 * Boundary values are inclusive. See the examples below.
187 * If boundary2 < boundary1, the values are swapped.
188 * If boundary1 == boundary2, value of boundary1 will be returned
189 *
190 * Generating boundary values for Uint8:
191 * BoundaryValues(UINT8_MAX, 10, 20, True) -> [10,11,19,20]
192 * BoundaryValues(UINT8_MAX, 10, 20, False) -> [9,21]
193 * BoundaryValues(UINT8_MAX, 0, 15, True) -> [0, 1, 14, 15]
194 * BoundaryValues(UINT8_MAX, 0, 15, False) -> [16]
195 * BoundaryValues(UINT8_MAX, 0, 0xFF, False) -> [0], error set
196 *
197 * Generator works the same for other types of unsigned integers.
198 *
199 * \param maxValue The biggest value that is acceptable for this data type.
200 * For instance, for Uint8 -> 255, Uint16 -> 65536 etc.
201 * \param boundary1 defines lower boundary
202 * \param boundary2 defines upper boundary
203 * \param validDomain Generate only for valid domain (for the data type)
204 *
205 * \returns Returns a random boundary value for the domain or 0 in case of error
206 */
207static Uint64
208SDLTest_GenerateUnsignedBoundaryValues(const Uint64 maxValue, Uint64 boundary1, Uint64 boundary2, SDL_bool validDomain)
209{
210 Uint64 b1, b2;
211 Uint64 delta;
212 Uint64 tempBuf[4];
213 Uint8 index;
214
215 /* Maybe swap */
216 if (boundary1 > boundary2) {
217 b1 = boundary2;
218 b2 = boundary1;
219 } else {
220 b1 = boundary1;
221 b2 = boundary2;
222 }
223
224 index = 0;
225 if (validDomain == SDL_TRUE) {
226 if (b1 == b2) {
227 return b1;
228 }
229
230 /* Generate up to 4 values within bounds */
231 delta = b2 - b1;
232 if (delta < 4) {
233 do {
234 tempBuf[index] = b1 + index;
235 index++;
236 } while (index < delta);
237 } else {
238 tempBuf[index] = b1;
239 index++;
240 tempBuf[index] = b1 + 1;
241 index++;
242 tempBuf[index] = b2 - 1;
243 index++;
244 tempBuf[index] = b2;
245 index++;
246 }
247 } else {
248 /* Generate up to 2 values outside of bounds */
249 if (b1 > 0) {
250 tempBuf[index] = b1 - 1;
251 index++;
252 }
253
254 if (b2 < maxValue) {
255 tempBuf[index] = b2 + 1;
256 index++;
257 }
258 }
259
260 if (index == 0) {
261 /* There are no valid boundaries */
262 SDL_Unsupported();
263 return 0;
264 }
265
266 return tempBuf[SDLTest_RandomUint8() % index];
267}
268
269
270Uint8
271SDLTest_RandomUint8BoundaryValue(Uint8 boundary1, Uint8 boundary2, SDL_bool validDomain)
272{
273 /* max value for Uint8 */
274 const Uint64 maxValue = UCHAR_MAX;
275 return (Uint8)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
276 (Uint64) boundary1, (Uint64) boundary2,
277 validDomain);
278}
279
280Uint16
281SDLTest_RandomUint16BoundaryValue(Uint16 boundary1, Uint16 boundary2, SDL_bool validDomain)
282{
283 /* max value for Uint16 */
284 const Uint64 maxValue = USHRT_MAX;
285 return (Uint16)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
286 (Uint64) boundary1, (Uint64) boundary2,
287 validDomain);
288}
289
290Uint32
291SDLTest_RandomUint32BoundaryValue(Uint32 boundary1, Uint32 boundary2, SDL_bool validDomain)
292{
293 /* max value for Uint32 */
294 #if ((ULONG_MAX) == (UINT_MAX))
295 const Uint64 maxValue = ULONG_MAX;
296 #else
297 const Uint64 maxValue = UINT_MAX;
298 #endif
299 return (Uint32)SDLTest_GenerateUnsignedBoundaryValues(maxValue,
300 (Uint64) boundary1, (Uint64) boundary2,
301 validDomain);
302}
303
304Uint64
305SDLTest_RandomUint64BoundaryValue(Uint64 boundary1, Uint64 boundary2, SDL_bool validDomain)
306{
307 /* max value for Uint64 */
308 const Uint64 maxValue = UINT64_MAX;
309 return SDLTest_GenerateUnsignedBoundaryValues(maxValue,
310 boundary1, boundary2,
311 validDomain);
312}
313
314/* !
315 * Generates a signed boundary value between the given boundaries.
316 * Boundary values are inclusive. See the examples below.
317 * If boundary2 < boundary1, the values are swapped.
318 * If boundary1 == boundary2, value of boundary1 will be returned
319 *
320 * Generating boundary values for Sint8:
321 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, True) -> [-10,-9,19,20]
322 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, False) -> [-11,21]
323 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -30, -15, True) -> [-30, -29, -16, -15]
324 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 15, False) -> [16]
325 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 127, False) -> [0], error set
326 *
327 * Generator works the same for other types of signed integers.
328 *
329 * \param minValue The smallest value that is acceptable for this data type.
330 * For instance, for Uint8 -> -127, etc.
331 * \param maxValue The biggest value that is acceptable for this data type.
332 * For instance, for Uint8 -> 127, etc.
333 * \param boundary1 defines lower boundary
334 * \param boundary2 defines upper boundary
335 * \param validDomain Generate only for valid domain (for the data type)
336 *
337 * \returns Returns a random boundary value for the domain or 0 in case of error
338 */
339static Sint64
340SDLTest_GenerateSignedBoundaryValues(const Sint64 minValue, const Sint64 maxValue, Sint64 boundary1, Sint64 boundary2, SDL_bool validDomain)
341{
342 Sint64 b1, b2;
343 Sint64 delta;
344 Sint64 tempBuf[4];
345 Uint8 index;
346
347 /* Maybe swap */
348 if (boundary1 > boundary2) {
349 b1 = boundary2;
350 b2 = boundary1;
351 } else {
352 b1 = boundary1;
353 b2 = boundary2;
354 }
355
356 index = 0;
357 if (validDomain == SDL_TRUE) {
358 if (b1 == b2) {
359 return b1;
360 }
361
362 /* Generate up to 4 values within bounds */
363 delta = b2 - b1;
364 if (delta < 4) {
365 do {
366 tempBuf[index] = b1 + index;
367 index++;
368 } while (index < delta);
369 } else {
370 tempBuf[index] = b1;
371 index++;
372 tempBuf[index] = b1 + 1;
373 index++;
374 tempBuf[index] = b2 - 1;
375 index++;
376 tempBuf[index] = b2;
377 index++;
378 }
379 } else {
380 /* Generate up to 2 values outside of bounds */
381 if (b1 > minValue) {
382 tempBuf[index] = b1 - 1;
383 index++;
384 }
385
386 if (b2 < maxValue) {
387 tempBuf[index] = b2 + 1;
388 index++;
389 }
390 }
391
392 if (index == 0) {
393 /* There are no valid boundaries */
394 SDL_Unsupported();
395 return minValue;
396 }
397
398 return tempBuf[SDLTest_RandomUint8() % index];
399}
400
401
402Sint8
403SDLTest_RandomSint8BoundaryValue(Sint8 boundary1, Sint8 boundary2, SDL_bool validDomain)
404{
405 /* min & max values for Sint8 */
406 const Sint64 maxValue = SCHAR_MAX;
407 const Sint64 minValue = SCHAR_MIN;
408 return (Sint8)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
409 (Sint64) boundary1, (Sint64) boundary2,
410 validDomain);
411}
412
413Sint16
414SDLTest_RandomSint16BoundaryValue(Sint16 boundary1, Sint16 boundary2, SDL_bool validDomain)
415{
416 /* min & max values for Sint16 */
417 const Sint64 maxValue = SHRT_MAX;
418 const Sint64 minValue = SHRT_MIN;
419 return (Sint16)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
420 (Sint64) boundary1, (Sint64) boundary2,
421 validDomain);
422}
423
424Sint32
425SDLTest_RandomSint32BoundaryValue(Sint32 boundary1, Sint32 boundary2, SDL_bool validDomain)
426{
427 /* min & max values for Sint32 */
428 #if ((ULONG_MAX) == (UINT_MAX))
429 const Sint64 maxValue = LONG_MAX;
430 const Sint64 minValue = LONG_MIN;
431 #else
432 const Sint64 maxValue = INT_MAX;
433 const Sint64 minValue = INT_MIN;
434 #endif
435 return (Sint32)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
436 (Sint64) boundary1, (Sint64) boundary2,
437 validDomain);
438}
439
440Sint64
441SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, SDL_bool validDomain)
442{
443 /* min & max values for Sint64 */
444 const Sint64 maxValue = INT64_MAX;
445 const Sint64 minValue = INT64_MIN;
446 return SDLTest_GenerateSignedBoundaryValues(minValue, maxValue,
447 boundary1, boundary2,
448 validDomain);
449}
450
451float
452SDLTest_RandomUnitFloat()
453{
454 return SDLTest_RandomUint32() / (float) UINT_MAX;
455}
456
457float
458SDLTest_RandomFloat()
459{
460 return (float) (SDLTest_RandomUnitDouble() * 2.0 * (double)FLT_MAX - (double)(FLT_MAX));
461}
462
463double
464SDLTest_RandomUnitDouble()
465{
466 return (double) (SDLTest_RandomUint64() >> 11) * (1.0/9007199254740992.0);
467}
468
469double
470SDLTest_RandomDouble()
471{
472 double r = 0.0;
473 double s = 1.0;
474 do {
475 s /= UINT_MAX + 1.0;
476 r += (double)SDLTest_RandomInt(&rndContext) * s;
477 } while (s > DBL_EPSILON);
478
479 fuzzerInvocationCounter++;
480
481 return r;
482}
483
484
485char *
486SDLTest_RandomAsciiString()
487{
488 return SDLTest_RandomAsciiStringWithMaximumLength(255);
489}
490
491char *
492SDLTest_RandomAsciiStringWithMaximumLength(int maxLength)
493{
494 int size;
495
496 if(maxLength < 1) {
497 SDL_InvalidParamError("maxLength");
498 return NULL;
499 }
500
501 size = (SDLTest_RandomUint32() % (maxLength + 1));
502
503 return SDLTest_RandomAsciiStringOfSize(size);
504}
505
506char *
507SDLTest_RandomAsciiStringOfSize(int size)
508{
509 char *string;
510 int counter;
511
512
513 if(size < 1) {
514 SDL_InvalidParamError("size");
515 return NULL;
516 }
517
518 string = (char *)SDL_malloc((size + 1) * sizeof(char));
519 if (string==NULL) {
520 return NULL;
521 }
522
523 for(counter = 0; counter < size; ++counter) {
524 string[counter] = (char)SDLTest_RandomIntegerInRange(32, 126);
525 }
526
527 string[counter] = '\0';
528
529 fuzzerInvocationCounter++;
530
531 return string;
532}
533
534/* vi: set ts=4 sw=4 expandtab: */
535