src/test/SDL_test_fuzzer.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 04 Jun 2014 10:56:56 -0700
changeset 8820 0e935d5b193a
parent 8149 681eb46b8ac4
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Added annotations to help code analysis tools

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