# raylib — CWE-407 Disclosure Brief

**Project:** raylib
**Disclosure date:** 2026-03-27
**Severity:** HIGH
**Speedup:** varies by defect
**Status:** PATCHED

---

## Finding

Two independent defects in raylib use linear search where O(1) hash structures are appropriate. The first (raylib-0001) performs O(G) glyph index lookup per codepoint on every text draw call, making text rendering O(G) per character. The second (raylib-0002) uses `std::find`-style linear deduplication when generating cellular noise images, producing O(n²) sequence deduplication.

## The Defect(s)

| ID | Location | Pattern | Complexity |
|----|----------|---------|------------|
| raylib-0001 | `src/rtext.c` | `GetGlyphIndex()` O(G) linear scan per codepoint per text draw call | O(G) per character, O(G×L) per string of length L |
| raylib-0002 | `src/rshapes.c` | `GenerateImageCellular()` random-sequence dedup O(n²) linear find | O(n²) per image generation |

## Complexity Proof

**raylib-0001:** Let G = number of glyphs loaded in a `Font` (typically 95–512 for ASCII/extended sets), L = length of string being rendered.

`GetGlyphIndex()` searches for a codepoint by scanning the `Font.glyphs` array linearly:

```c
for (int i = 0; i < font.glyphCount; i++) {
    if (font.glyphs[i].value == codepoint) return i;
}
```

This is O(G) per call. `DrawText()` and related functions call `GetGlyphIndex()` once per character in the string:

```
L characters × O(G) scan = O(L×G) per DrawText call
```

With a pre-built `unordered_map<int, int>` from codepoint to glyph index, each lookup is O(1):

```
O(G) to build map + O(L) for rendering = O(G + L)
```

For G=256, L=100: defective = 25,600 ops per DrawText; fixed = 356 ops.

**raylib-0002:** Let n = number of seeds/points used in cellular noise generation.

`GenerateImageCellular()` generates n random seed positions and deduplicates them using a growing array with linear-scan membership check:

```
Insert seed 1: check list of 0   → O(0)
Insert seed 2: check list of 1   → O(1)
...
Insert seed n: check list of n-1 → O(n-1)
Total: 0+1+...+(n-1) = n(n-1)/2 = O(n²)
```

With a `HashSet` tracking inserted positions: O(n) total.

## Impact

raylib-0001 affects any raylib application rendering text with non-trivial string length or font sizes, including game UIs, debug overlays, and text-heavy applications. Since `GetGlyphIndex()` is on the hot path of every `DrawText` call in the game loop (typically called 60+ times per second), the O(G) overhead per character is multiplied by frame rate and string length.

raylib-0002 affects applications using `GenerateImageCellular()` for procedural texture generation. While not a per-frame operation, large cellular images with many seed points experience quadratic generation time.

## The Fix

**raylib-0001:** At `LoadFont` time, build a `HashMap<int codepoint, int glyphIndex>` alongside the glyphs array. In `GetGlyphIndex()`, perform a hash lookup instead of a linear scan.

**raylib-0002:** In `GenerateImageCellular()`, replace the dedup array with an `unordered_set<uint64_t>` (encoding x,y as a single 64-bit key). Check and insert in O(1).

## Patch

```diff
// raylib-0001: rtext.c
+ // At LoadFont time:
+ // font.glyphMap = HashMap mapping codepoint -> index (built once)

  int GetGlyphIndex(Font font, int codepoint) {
-     for (int i = 0; i < font.glyphCount; i++) {
-         if (font.glyphs[i].value == codepoint) return i;
-     }
-     return 0;
+     return font.glyphMap[codepoint];  // O(1) hash lookup
  }

// raylib-0002: rshapes.c
- int *seeds = ...; int seedCount = 0;
- // ... linear dedup ...
- bool found = false;
- for (int j = 0; j < seedCount; j++)
-     if (seeds[j] == pos) { found = true; break; }
- if (!found) seeds[seedCount++] = pos;
+ unordered_set<int> seedSet;
+ // O(1) insert-and-check:
+ if (seedSet.insert(pos).second) seeds[seedCount++] = pos;
```

## What We Ask

Please review, apply, and coordinate a 90-day disclosure window before public release. Reply to security@undefect.com.

---

*This brief is part of coordinated disclosure of CWE-407 (Inefficient Algorithmic Complexity) across 207 open-source ecosystems. Full report: https://undefect.com*
