From d4b8ff7f9d118f62c1f72cce0d70ab9efbf5f26d Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Mon, 27 Jul 2026 22:07:56 -0400 Subject: [PATCH] Fix polygon OOB reads and config macro --- include/raylib-nuklear.h | 23 ++++++++++++------- test/raylib-nuklear-test.c | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/include/raylib-nuklear.h b/include/raylib-nuklear.h index 71400c5..3f80313 100644 --- a/include/raylib-nuklear.h +++ b/include/raylib-nuklear.h @@ -157,6 +157,15 @@ extern "C" { #define RAYLIB_NUKLEAR_FONT_SPACING_RATIO 0.01f #endif // RAYLIB_NUKLEAR_FONT_SPACING_RATIO +#ifndef RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS +/** + * The maximum amount of points allowed when drawing a filled polygon. + * + * @see NK_COMMAND_POLYGON_FILLED + */ +#define RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS 64 +#endif // RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS + #ifndef RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS /** * The amount of segments used when drawing an arc. @@ -563,9 +572,6 @@ NuklearImageToTexture(struct nk_image img) */ static void raylib_nuklear_draw_polygon_fill(float scale, const struct nk_vec2i *pnts, int count, Color col) { int i = 0; - #ifndef RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS - #define RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS 64 - #endif int left = 10000, top = 10000, bottom = 0, right = 0; int nodes, nodeX[RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS], pixelX, pixelY, j, swap ; @@ -620,7 +626,7 @@ static void raylib_nuklear_draw_polygon_fill(float scale, const struct nk_vec2i } else i++; } /* Fill the pixels between node pairs. */ - for (i = 0; i < nodes; i += 2) { + for (i = 0; i + 1 < nodes; i += 2) { if (nodeX[i+0] >= right) break; if (nodeX[i+1] > left) { if (nodeX[i+0] < left) nodeX[i+0] = left ; @@ -632,7 +638,6 @@ static void raylib_nuklear_draw_polygon_fill(float scale, const struct nk_vec2i } } } - #undef RAYLIB_NUKLEAR_POLYGON_FILL_MAX_POINTS } /** @@ -829,9 +834,11 @@ DrawNuklear(struct nk_context * ctx) Vector2 end = {(float)p->points[i + 1].x * scale, (float)p->points[i + 1].y * scale}; DrawLineEx(start, end, thickness, color); } - Vector2 last = {(float)p->points[p->point_count - 1].x * scale, (float)p->points[p->point_count - 1].y * scale}; - Vector2 first = {(float)p->points[0].x * scale, (float)p->points[0].y * scale}; - DrawLineEx(last, first, thickness, color); + if (p->point_count >= 2) { + Vector2 last = {(float)p->points[p->point_count - 1].x * scale, (float)p->points[p->point_count - 1].y * scale}; + Vector2 first = {(float)p->points[0].x * scale, (float)p->points[0].y * scale}; + DrawLineEx(last, first, thickness, color); + } } break; case NK_COMMAND_POLYGON_FILLED: { diff --git a/test/raylib-nuklear-test.c b/test/raylib-nuklear-test.c index e439be9..b25d45c 100644 --- a/test/raylib-nuklear-test.c +++ b/test/raylib-nuklear-test.c @@ -202,6 +202,51 @@ int main(int argc, char *argv[]) { UnloadNuklear(ctx); } + // Degenerate polygons must not crash DrawNuklear(). + // https://github.com/RobLoach/raylib-nuklear/issues/131 + { + ctx = InitNuklear(10); + Assert(ctx); + + UpdateNuklear(ctx); + + if (nk_begin(ctx, "PolygonTest", nk_rect(0, 0, 100, 100), + NK_WINDOW_NO_SCROLLBAR)) { + struct nk_command_buffer* canvas = nk_window_get_canvas(ctx); + struct nk_color color = nk_rgb(230, 20, 20); + + // No points. + nk_fill_polygon(canvas, NULL, 0, color); + nk_stroke_polygon(canvas, NULL, 0, 1.0f, color); + + // A single point. + float single[] = {10.0f, 10.0f}; + nk_fill_polygon(canvas, single, 1, color); + nk_stroke_polygon(canvas, single, 1, 1.0f, color); + + // A self-touching polygon, where a repeated vertex touches the + // outline and can leave the scanline fill with an odd node count. + float touching[] = { + 10.0f, 10.0f, + 30.0f, 10.0f, + 20.0f, 20.0f, + 30.0f, 30.0f, + 10.0f, 30.0f, + 20.0f, 20.0f + }; + nk_fill_polygon(canvas, touching, 6, color); + nk_stroke_polygon(canvas, touching, 6, 1.0f, color); + } + nk_end(ctx); + + BeginDrawing(); + ClearBackground(RAYWHITE); + DrawNuklear(ctx); + EndDrawing(); + + UnloadNuklear(ctx); + } + // A NULL context must not crash any of the public entry points. { UpdateNuklear(NULL);