|
| 1 | +#include <cgif.h> |
| 2 | +#include <stdlib.h> |
| 3 | +#include <string.h> |
| 4 | +#include <stdio.h> |
| 5 | +#include <stdint.h> |
| 6 | + |
| 7 | +static int writecb(void* pContext, const uint8_t* pData, size_t size) { |
| 8 | + (void)pContext; (void)pData; (void)size; |
| 9 | + return 0; |
| 10 | +} |
| 11 | + |
| 12 | +int main() { |
| 13 | + /* |
| 14 | + * before treeNode.mean in cgif_rgb.c was changed from float to double: Heap buffer over-read in cgif_rgb.c crawl_decision_tree() |
| 15 | + * |
| 16 | + * Float precision bug in mean-cut color quantization. |
| 17 | + * When dominant color (246,0,0) has freq 545600 and rare color |
| 18 | + * (247,0,0) has freq 1, the float mean computation: |
| 19 | + * mean = (float)(545600*246 + 1*247) / (float)(545600+1) |
| 20 | + * = (float)(134217847) / (float)(545601) |
| 21 | + * = 134217840.0 / 545601.0 (numerator lost precision!) |
| 22 | + * = 245.999985 < 246 |
| 23 | + * |
| 24 | + * This causes the partition loop in crawl_decision_tree to never |
| 25 | + * advance, producing a child node with invalid range |
| 26 | + * [idxMin, idxMin-1] = [idxMin, UINT32_MAX], causing a massive |
| 27 | + * heap buffer over-read in get_mean/get_variance. |
| 28 | + * |
| 29 | + * Dimensions: 192 x 2843 = 545856 pixels |
| 30 | + * 255 cloud colors + 1 rare + 545600 dominant = 545856 |
| 31 | + */ |
| 32 | + |
| 33 | + uint16_t w = 192; |
| 34 | + uint16_t h = 2843; |
| 35 | + uint32_t numPixel = (uint32_t)w * h; |
| 36 | + |
| 37 | + fprintf(stderr, "Image: %ux%u = %u pixels\n", w, h, numPixel); |
| 38 | + |
| 39 | + uint8_t* imgData = malloc(numPixel * 3); |
| 40 | + if (!imgData) { |
| 41 | + fprintf(stderr, "malloc failed\n"); |
| 42 | + return 1; |
| 43 | + } |
| 44 | + |
| 45 | + uint32_t idx = 0; |
| 46 | + |
| 47 | + /* 255 cloud colors: R=246, G=1..255, B=0 (each appears 1x) |
| 48 | + * These share R=246 with the dominant color so they'll be |
| 49 | + * in the same partition region along the R dimension. |
| 50 | + * Total unique colors = 255 + 1 + 1 = 257 > 255, forcing quantization. |
| 51 | + */ |
| 52 | + for (int g = 1; g <= 255; g++, idx++) { |
| 53 | + imgData[idx * 3 + 0] = 246; |
| 54 | + imgData[idx * 3 + 1] = g; |
| 55 | + imgData[idx * 3 + 2] = 0; |
| 56 | + } |
| 57 | + |
| 58 | + /* 1 pixel of rare color: R=247, G=0, B=0 */ |
| 59 | + imgData[idx * 3 + 0] = 247; |
| 60 | + imgData[idx * 3 + 1] = 0; |
| 61 | + imgData[idx * 3 + 2] = 0; |
| 62 | + idx++; |
| 63 | + |
| 64 | + /* Remaining 545600 pixels: dominant color R=246, G=0, B=0 */ |
| 65 | + uint32_t dominant_freq = numPixel - idx; |
| 66 | + fprintf(stderr, "Dominant color (246,0,0) freq: %u (need exactly 545600)\n", dominant_freq); |
| 67 | + fprintf(stderr, "Rare color (247,0,0) freq: 1\n"); |
| 68 | + fprintf(stderr, "Cloud colors (246,1-255,0): 255\n"); |
| 69 | + fprintf(stderr, "Total unique colors: 257\n"); |
| 70 | + |
| 71 | + for (; idx < numPixel; idx++) { |
| 72 | + imgData[idx * 3 + 0] = 246; |
| 73 | + imgData[idx * 3 + 1] = 0; |
| 74 | + imgData[idx * 3 + 2] = 0; |
| 75 | + } |
| 76 | + |
| 77 | + /* Verify the float precision bug condition */ |
| 78 | + float num = (float)((uint64_t)545600 * 246 + (uint64_t)1 * 247); |
| 79 | + float den = (float)(545600 + 1); |
| 80 | + float mean = num / den; |
| 81 | + fprintf(stderr, "\nFloat precision check:\n"); |
| 82 | + fprintf(stderr, " mean = %.15f (should be >= 246.0)\n", mean); |
| 83 | + fprintf(stderr, " mean < 246.0? %s\n", mean < 246.0f ? "YES - BUG WILL TRIGGER" : "NO"); |
| 84 | + |
| 85 | + /* Create GIF */ |
| 86 | + CGIFrgb_Config config = {0}; |
| 87 | + config.width = w; |
| 88 | + config.height = h; |
| 89 | + config.pWriteFn = writecb; |
| 90 | + |
| 91 | + CGIFrgb* pGIF = cgif_rgb_newgif(&config); |
| 92 | + if (!pGIF) { |
| 93 | + fprintf(stderr, "cgif_rgb_newgif failed\n"); |
| 94 | + free(imgData); |
| 95 | + return 1; |
| 96 | + } |
| 97 | + |
| 98 | + CGIFrgb_FrameConfig fconfig = {0}; |
| 99 | + fconfig.pImageData = imgData; |
| 100 | + fconfig.fmtChan = CGIF_CHAN_FMT_RGB; |
| 101 | + fconfig.delay = 10; |
| 102 | + |
| 103 | + fprintf(stderr, "\nCalling cgif_rgb_addframe...\n"); |
| 104 | + cgif_result r = cgif_rgb_addframe(pGIF, &fconfig); |
| 105 | + fprintf(stderr, "Result: %d\n", r); |
| 106 | + |
| 107 | + r = cgif_rgb_close(pGIF); |
| 108 | + free(imgData); |
| 109 | + return 0; |
| 110 | +} |
0 commit comments