Skip to content

[Audit][High] Off-by-one type mismatch in OverworldV2Generator tree/vegetation placement bounds check #707

@MichaelFisher1997

Description

@MichaelFisher1997

🔍 Module Scanned

modules/worldgen-overworld-v2/src/ (automated audit scan)

📝 Summary

In OverworldV2Generator, the tree placement and vegetation placement bounds checks compare terrain_height (i32) directly against CHUNK_SIZE_Y - 8 (u32 constant 248), causing a Zig signed-to-unsigned comparison that produces incorrect results when terrain_height > 248. This causes trees and vegetation to be incorrectly skipped at high altitudes (mountain peaks, jagged peaks).

📍 Location

  • File: modules/worldgen-overworld-v2/src/root.zig:231
  • Function/Scope: placeTrees() and placeVegetation()

🔴 Severity: High

  • High: Incorrect rendering (missing trees/vegetation at high altitudes), broken features in mountainous terrain

💥 Impact

When terrain_height >= 248 (which easily occurs at mountainous peaks with sea_level=64):

  • The comparison terrain_height >= CHUNK_SIZE_Y - 8 evaluates as terrain_height >= 248
  • For terrain_height = 300, Zig performs 300 >= 248 = true, incorrectly skipping tree placement
  • This affects trees (line 231) and vegetation (line 280), which both use the same boundary check pattern
  • In mountainous worlds with peak heights of 140+ sea_level (204+ blocks), all trees are incorrectly suppressed

🔎 Evidence

Line 231 in placeTrees():

if (surface_y <= self.params.sea_level or surface_y >= CHUNK_SIZE_Y - 8) continue;

Line 280 in placeVegetation():

if (surface_y <= 0 or surface_y >= CHUNK_SIZE_Y - 2) continue;

The issue is the type mismatch in the comparison:

  • surface_y is i32 (from chunk.getSurfaceHeight() which returns i16 promoted to i32)
  • CHUNK_SIZE_Y is u32 = 256 (from world_core.CHUNK_SIZE_Y)
  • CHUNK_SIZE_Y - 8 evaluates to u2 248 (truncated from u32)
  • Zig performs signed-to-unsigned comparison, causing terrain heights > 248 to wrap

🛠️ Proposed Fix

Change the boundary checks to use explicit integer type casting:

// Line 231 - change from:
if (surface_y <= self.params.sea_level or surface_y >= CHUNK_SIZE_Y - 8) continue;
// To:
if (surface_y <= self.params.sea_level or surface_y >= @as(i32, CHUNK_SIZE_Y) - 8) continue;

// Line 280 - change from:
if (surface_y <= 0 or surface_y >= CHUNK_SIZE_Y - 2) continue;
// To:
if (surface_y <= 0 or surface_y >= @as(i32, CHUNK_SIZE_Y) - 2) continue;

Or equivalently, cast the upper bound to i32:

if (surface_y <= self.params.sea_level or surface_y >= @as(i32, CHUNK_SIZE_Y - 8)) continue;

✅ Acceptance Criteria

  • Trees spawn correctly at terrain heights >= 248
  • Vegetation spawns correctly at terrain heights >= 254
  • Unit test verifies tree placement at mountain peaks (height ~140 with sea_level=64)
  • Build succeeds with nix develop --command zig build

📚 References

Metadata

Metadata

Assignees

No one assigned

    Labels

    automated-auditIssues found by automated opencode audit scansbugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions