Atlas - SDL_test_fuzzer.c

Home / ext / SDL / src / test Lines: 1 | Size: 13685 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#include <SDL3/SDL_test.h> 28 29#include <float.h> /* Needed for FLT_MAX and DBL_EPSILON */ 30#include <limits.h> /* Needed for UCHAR_MAX, etc. */ 31 32/** 33 * Counter for fuzzer invocations 34 */ 35static int fuzzerInvocationCounter = 0; 36 37/** 38 * Context for shared random number generator 39 */ 40static Uint64 rndContext; 41 42/* 43 * Note: doxygen documentation markup for functions is in the header file. 44 */ 45 46void SDLTest_FuzzerInit(Uint64 execKey) 47{ 48 rndContext = execKey; 49 fuzzerInvocationCounter = 0; 50} 51 52int SDLTest_GetFuzzerInvocationCount(void) 53{ 54 return fuzzerInvocationCounter; 55} 56 57Uint8 SDLTest_RandomUint8(void) 58{ 59 fuzzerInvocationCounter++; 60 61 return (Uint8)(SDL_rand_bits_r(&rndContext) >> 24); 62} 63 64Sint8 SDLTest_RandomSint8(void) 65{ 66 fuzzerInvocationCounter++; 67 68 return (Sint8)(SDL_rand_bits_r(&rndContext) >> 24); 69} 70 71Uint16 SDLTest_RandomUint16(void) 72{ 73 fuzzerInvocationCounter++; 74 75 return (Uint16)(SDL_rand_bits_r(&rndContext) >> 16); 76} 77 78Sint16 SDLTest_RandomSint16(void) 79{ 80 fuzzerInvocationCounter++; 81 82 return (Sint16)(SDL_rand_bits_r(&rndContext) >> 16); 83} 84 85Uint32 SDLTest_RandomUint32(void) 86{ 87 fuzzerInvocationCounter++; 88 89 return SDL_rand_bits_r(&rndContext); 90} 91 92Sint32 SDLTest_RandomSint32(void) 93{ 94 fuzzerInvocationCounter++; 95 96 return (Sint32)SDL_rand_bits_r(&rndContext); 97} 98 99Uint64 SDLTest_RandomUint64(void) 100{ 101 union 102 { 103 Uint64 v64; 104 Uint32 v32[2]; 105 } value; 106 107 fuzzerInvocationCounter++; 108 109 value.v32[0] = SDLTest_RandomUint32(); 110 value.v32[1] = SDLTest_RandomUint32(); 111 112 return value.v64; 113} 114 115Sint64 SDLTest_RandomSint64(void) 116{ 117 union 118 { 119 Uint64 v64; 120 Uint32 v32[2]; 121 } value; 122 123 fuzzerInvocationCounter++; 124 125 value.v32[0] = SDLTest_RandomUint32(); 126 value.v32[1] = SDLTest_RandomUint32(); 127 128 return (Sint64)value.v64; 129} 130 131Sint32 SDLTest_RandomIntegerInRange(Sint32 min, Sint32 max) 132{ 133 fuzzerInvocationCounter++; 134 135 if (min == max) { 136 return min; 137 } 138 139 if (min > max) { 140 Sint32 temp = min; 141 min = max; 142 max = temp; 143 } 144 145 Uint64 range = (Sint64)max - (Sint64)min; 146 if (range < SDL_MAX_SINT32) { 147 return min + SDL_rand_r(&rndContext, (Sint32) range + 1); 148 } else { 149 Uint64 add = SDL_rand_bits_r(&rndContext) | ((Uint64) SDL_rand_bits_r(&rndContext) << 32); 150 return (Sint32) (min + (Sint64) (add % (range + 1))); 151 } 152} 153 154/** 155 * Generates a unsigned boundary value between the given boundaries. 156 * Boundary values are inclusive. See the examples below. 157 * If boundary2 < boundary1, the values are swapped. 158 * If boundary1 == boundary2, value of boundary1 will be returned 159 * 160 * Generating boundary values for Uint8: 161 * BoundaryValues(UINT8_MAX, 10, 20, True) -> [10,11,19,20] 162 * BoundaryValues(UINT8_MAX, 10, 20, False) -> [9,21] 163 * BoundaryValues(UINT8_MAX, 0, 15, True) -> [0, 1, 14, 15] 164 * BoundaryValues(UINT8_MAX, 0, 15, False) -> [16] 165 * BoundaryValues(UINT8_MAX, 0, 0xFF, False) -> [0], error set 166 * 167 * Generator works the same for other types of unsigned integers. 168 * 169 * \param maxValue The biggest value that is acceptable for this data type. 170 * For instance, for Uint8 -> 255, Uint16 -> 65536 etc. 171 * \param boundary1 defines lower boundary 172 * \param boundary2 defines upper boundary 173 * \param validDomain Generate only for valid domain (for the data type) 174 * 175 * \returns Returns a random boundary value for the domain or 0 in case of error 176 */ 177static Uint64 SDLTest_GenerateUnsignedBoundaryValues(const Uint64 maxValue, Uint64 boundary1, Uint64 boundary2, bool validDomain) 178{ 179 Uint64 b1, b2; 180 Uint64 delta; 181 Uint64 tempBuf[4]; 182 Uint8 index; 183 184 /* Maybe swap */ 185 if (boundary1 > boundary2) { 186 b1 = boundary2; 187 b2 = boundary1; 188 } else { 189 b1 = boundary1; 190 b2 = boundary2; 191 } 192 193 index = 0; 194 if (validDomain == true) { 195 if (b1 == b2) { 196 return b1; 197 } 198 199 /* Generate up to 4 values within bounds */ 200 delta = b2 - b1; 201 if (delta < 4) { 202 do { 203 tempBuf[index] = b1 + index; 204 index++; 205 } while (index < delta); 206 } else { 207 tempBuf[index] = b1; 208 index++; 209 tempBuf[index] = b1 + 1; 210 index++; 211 tempBuf[index] = b2 - 1; 212 index++; 213 tempBuf[index] = b2; 214 index++; 215 } 216 } else { 217 /* Generate up to 2 values outside of bounds */ 218 if (b1 > 0) { 219 tempBuf[index] = b1 - 1; 220 index++; 221 } 222 223 if (b2 < maxValue) { 224 tempBuf[index] = b2 + 1; 225 index++; 226 } 227 } 228 229 if (index == 0) { 230 /* There are no valid boundaries */ 231 SDL_Unsupported(); 232 return 0; 233 } 234 235 return tempBuf[SDLTest_RandomUint8() % index]; 236} 237 238Uint8 SDLTest_RandomUint8BoundaryValue(Uint8 boundary1, Uint8 boundary2, bool validDomain) 239{ 240 /* max value for Uint8 */ 241 const Uint64 maxValue = UCHAR_MAX; 242 return (Uint8)SDLTest_GenerateUnsignedBoundaryValues(maxValue, 243 (Uint64)boundary1, (Uint64)boundary2, 244 validDomain); 245} 246 247Uint16 SDLTest_RandomUint16BoundaryValue(Uint16 boundary1, Uint16 boundary2, bool validDomain) 248{ 249 /* max value for Uint16 */ 250 const Uint64 maxValue = USHRT_MAX; 251 return (Uint16)SDLTest_GenerateUnsignedBoundaryValues(maxValue, 252 (Uint64)boundary1, (Uint64)boundary2, 253 validDomain); 254} 255 256Uint32 SDLTest_RandomUint32BoundaryValue(Uint32 boundary1, Uint32 boundary2, bool validDomain) 257{ 258/* max value for Uint32 */ 259#if ((ULONG_MAX) == (UINT_MAX)) 260 const Uint64 maxValue = ULONG_MAX; 261#else 262 const Uint64 maxValue = UINT_MAX; 263#endif 264 return (Uint32)SDLTest_GenerateUnsignedBoundaryValues(maxValue, 265 (Uint64)boundary1, (Uint64)boundary2, 266 validDomain); 267} 268 269Uint64 SDLTest_RandomUint64BoundaryValue(Uint64 boundary1, Uint64 boundary2, bool validDomain) 270{ 271 /* max value for Uint64 */ 272 const Uint64 maxValue = UINT64_MAX; 273 return SDLTest_GenerateUnsignedBoundaryValues(maxValue, 274 boundary1, boundary2, 275 validDomain); 276} 277 278/** 279 * Generates a signed boundary value between the given boundaries. 280 * Boundary values are inclusive. See the examples below. 281 * If boundary2 < boundary1, the values are swapped. 282 * If boundary1 == boundary2, value of boundary1 will be returned 283 * 284 * Generating boundary values for Sint8: 285 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, True) -> [-10,-9,19,20] 286 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -10, 20, False) -> [-11,21] 287 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -30, -15, True) -> [-30, -29, -16, -15] 288 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 15, False) -> [16] 289 * SignedBoundaryValues(SCHAR_MIN, SCHAR_MAX, -127, 127, False) -> [0], error set 290 * 291 * Generator works the same for other types of signed integers. 292 * 293 * \param minValue The smallest value that is acceptable for this data type. 294 * For instance, for Uint8 -> -127, etc. 295 * \param maxValue The biggest value that is acceptable for this data type. 296 * For instance, for Uint8 -> 127, etc. 297 * \param boundary1 defines lower boundary 298 * \param boundary2 defines upper boundary 299 * \param validDomain Generate only for valid domain (for the data type) 300 * 301 * \returns Returns a random boundary value for the domain or 0 in case of error 302 */ 303static Sint64 SDLTest_GenerateSignedBoundaryValues(const Sint64 minValue, const Sint64 maxValue, Sint64 boundary1, Sint64 boundary2, bool validDomain) 304{ 305 Sint64 b1, b2; 306 Sint64 delta; 307 Sint64 tempBuf[4]; 308 Uint8 index; 309 310 /* Maybe swap */ 311 if (boundary1 > boundary2) { 312 b1 = boundary2; 313 b2 = boundary1; 314 } else { 315 b1 = boundary1; 316 b2 = boundary2; 317 } 318 319 index = 0; 320 if (validDomain == true) { 321 if (b1 == b2) { 322 return b1; 323 } 324 325 /* Generate up to 4 values within bounds */ 326 delta = b2 - b1; 327 if (delta < 4) { 328 do { 329 tempBuf[index] = b1 + index; 330 index++; 331 } while (index < delta); 332 } else { 333 tempBuf[index] = b1; 334 index++; 335 tempBuf[index] = b1 + 1; 336 index++; 337 tempBuf[index] = b2 - 1; 338 index++; 339 tempBuf[index] = b2; 340 index++; 341 } 342 } else { 343 /* Generate up to 2 values outside of bounds */ 344 if (b1 > minValue) { 345 tempBuf[index] = b1 - 1; 346 index++; 347 } 348 349 if (b2 < maxValue) { 350 tempBuf[index] = b2 + 1; 351 index++; 352 } 353 } 354 355 if (index == 0) { 356 /* There are no valid boundaries */ 357 SDL_Unsupported(); 358 return minValue; 359 } 360 361 return tempBuf[SDLTest_RandomUint8() % index]; 362} 363 364Sint8 SDLTest_RandomSint8BoundaryValue(Sint8 boundary1, Sint8 boundary2, bool validDomain) 365{ 366 /* min & max values for Sint8 */ 367 const Sint64 maxValue = SCHAR_MAX; 368 const Sint64 minValue = SCHAR_MIN; 369 return (Sint8)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue, 370 (Sint64)boundary1, (Sint64)boundary2, 371 validDomain); 372} 373 374Sint16 SDLTest_RandomSint16BoundaryValue(Sint16 boundary1, Sint16 boundary2, bool validDomain) 375{ 376 /* min & max values for Sint16 */ 377 const Sint64 maxValue = SHRT_MAX; 378 const Sint64 minValue = SHRT_MIN; 379 return (Sint16)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue, 380 (Sint64)boundary1, (Sint64)boundary2, 381 validDomain); 382} 383 384Sint32 SDLTest_RandomSint32BoundaryValue(Sint32 boundary1, Sint32 boundary2, bool validDomain) 385{ 386/* min & max values for Sint32 */ 387#if ((ULONG_MAX) == (UINT_MAX)) 388 const Sint64 maxValue = LONG_MAX; 389 const Sint64 minValue = LONG_MIN; 390#else 391 const Sint64 maxValue = INT_MAX; 392 const Sint64 minValue = INT_MIN; 393#endif 394 return (Sint32)SDLTest_GenerateSignedBoundaryValues(minValue, maxValue, 395 (Sint64)boundary1, (Sint64)boundary2, 396 validDomain); 397} 398 399Sint64 SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, bool validDomain) 400{ 401 /* min & max values for Sint64 */ 402 const Sint64 maxValue = INT64_MAX; 403 const Sint64 minValue = INT64_MIN; 404 return SDLTest_GenerateSignedBoundaryValues(minValue, maxValue, 405 boundary1, boundary2, 406 validDomain); 407} 408 409float SDLTest_RandomUnitFloat(void) 410{ 411 return SDL_randf_r(&rndContext); 412} 413 414float SDLTest_RandomFloat(void) 415{ 416 union 417 { 418 float f; 419 Uint32 v32; 420 } value; 421 422 do { 423 value.v32 = SDLTest_RandomUint32(); 424 } while (SDL_isnanf(value.f) || SDL_isinff(value.f)); 425 426 return value.f; 427} 428 429double SDLTest_RandomUnitDouble(void) 430{ 431 return (double)(SDLTest_RandomUint64() >> (64-53)) * 0x1.0p-53; 432} 433 434double SDLTest_RandomDouble(void) 435{ 436 union 437 { 438 double d; 439 Uint64 v64; 440 } value; 441 442 do { 443 value.v64 = SDLTest_RandomUint64(); 444 } while (SDL_isnan(value.d) || SDL_isinf(value.d)); 445 446 return value.d; 447} 448 449char *SDLTest_RandomAsciiString(void) 450{ 451 return SDLTest_RandomAsciiStringWithMaximumLength(255); 452} 453 454char *SDLTest_RandomAsciiStringWithMaximumLength(int maxLength) 455{ 456 int size; 457 458 if (maxLength < 1) { 459 SDL_InvalidParamError("maxLength"); 460 return NULL; 461 } 462 463 size = (SDLTest_RandomUint32() % (maxLength + 1)); 464 if (size == 0) { 465 size = 1; 466 } 467 return SDLTest_RandomAsciiStringOfSize(size); 468} 469 470char *SDLTest_RandomAsciiStringOfSize(int size) 471{ 472 char *string; 473 int counter; 474 475 if (size < 1) { 476 SDL_InvalidParamError("size"); 477 return NULL; 478 } 479 480 string = (char *)SDL_malloc((size + 1) * sizeof(char)); 481 if (!string) { 482 return NULL; 483 } 484 485 for (counter = 0; counter < size; ++counter) { 486 string[counter] = (char)SDLTest_RandomIntegerInRange(32, 126); 487 } 488 489 string[counter] = '\0'; 490 491 fuzzerInvocationCounter++; 492 493 return string; 494} 495
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.