Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[models] UBSAN flags 0 offset to NULL in DrawMesh #1891

Closed
3 tasks done
rcorre opened this issue Jul 25, 2021 · 16 comments
Closed
3 tasks done

[models] UBSAN flags 0 offset to NULL in DrawMesh #1891

rcorre opened this issue Jul 25, 2021 · 16 comments

Comments

@rcorre
Copy link
Contributor

rcorre commented Jul 25, 2021

WARNING: Please, read this note carefully before submitting a new issue:

It is important to realise that this is NOT A SUPPORT FORUM, this is for reproducible BUGS with raylib ONLY.

There are lots of generous and helpful people ready to help you out on raylib Discord forum or raylib reddit.

Remember that asking for support questions here actively takes developer time away from improving raylib.


Please, before submitting a new issue verify and check:

  • I tested it on latest raylib version from master branch
  • I checked there is no similar issue already reported
  • My code has no errors or misuse of raylib

Issue description

Briefly describe the issue you are experiencing (or the feature you want to see added to raylib). Tell us what you were trying to do and what happened instead. Remember, this is not the best place to ask questions. For questions, go to raylib Discord server.

UBSAN flags

if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
as undefined behavior (adding an offset to a NULL pointer, which happens at

raylib/src/rlgl.h

Line 3124 in 87b5420

glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short*)buffer + offset);
)

rlgl.h:3124:84: runtime error: applying zero offset to null pointer

From some reading around (e.g. https://patchwork.kernel.org/project/git/patch/[email protected]/), it sounds like adding any offset (even 0) to NULL is technically undefined behavior.

This was introduced sometime between raylib 3.5.0 and raylib 3.7.0, and still exists on master.

Environment

Linux, desktop.

Issue Screenshot

If possible, provide a screenshot that illustrates the issue. Usually an image is better than a thousand words.

Code Example

Provide minimal reproduction code to test the issue. Please, format the code properly and try to keep it as simple as possible, just focusing on the experienced issue.

  1. Compile raylib with the undefined behavior sanitizer
  2. Run shaders_basic_lighting example
@rcorre
Copy link
Contributor Author

rcorre commented Jul 25, 2021

Actually I'm kind of confused by this line anyways:

            if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);

Why check if indices is non-null, only to pass 0? Is that supposed to be

        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);

instead?

@raysan5
Copy link
Owner

raysan5 commented Jul 27, 2021

@rcorre Good catch! Reviewed it!

@raysan5 raysan5 closed this as completed Jul 27, 2021
@rcorre
Copy link
Contributor Author

rcorre commented Jul 28, 2021

Oops, that might have been the wrong suggestion, sorrry :(

I now get a SIGABRT on shaders_basic_lighting:

Program received signal SIGABRT, Aborted.
0x00007ffff714ad22 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff714ad22 in raise () from /usr/lib/libc.so.6
#1  0x00007ffff7134862 in abort () from /usr/lib/libc.so.6
#2  0x00007ffff4c5ded9 in ?? () from /usr/lib/libnvidia-glcore.so.470.57.02
#3  0x00007ffff4dd46aa in ?? () from /usr/lib/libnvidia-glcore.so.470.57.02
#4  0x00007ffff4d80a89 in ?? () from /usr/lib/libnvidia-glcore.so.470.57.02
#5  0x00007ffff4c469e1 in ?? () from /usr/lib/libnvidia-glcore.so.470.57.02
#6  0x00007ffff648607f in ?? () from /usr/lib/libGLX_nvidia.so.0
#7  0x00007ffff6451620 in ?? () from /usr/lib/libGLX_nvidia.so.0
#8  0x0000555555a2f7d6 in swapBuffersGLX (window=0x555556745dd0) at ./external/glfw/src/glx_context.c:187
#9  0x0000555555994883 in glfwSwapBuffers (handle=0x555556745dd0) at ./external/glfw/src/context.c:653
#10 0x00005555558223a0 in SwapScreenBuffer () at core.c:4470
#11 0x0000555555821987 in EndDrawing () at core.c:1975
#12 0x00005555557b7952 in main () at shaders/shaders_basic_lighting.c:137

@raysan5
Copy link
Owner

raysan5 commented Jul 28, 2021

@rcorre Actually, my bad. I should have reviewed this issue more carefully. On the DrawMeshInstanced() function, previous to the draw call, I'm calling:

if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);

That call already binds the mesh.indices buffer:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);

That function is explained in the official OpenGL documentation, here the relevant part:

While a non-zero buffer object is bound to the GL_ELEMENT_ARRAY_BUFFER target, 
the indices parameter of glDrawElements, glDrawElementsInstanced, glDrawElementsBaseVertex, 
glDrawRangeElements, glDrawRangeElementsBaseVertex, glMultiDrawElements, or glMultiDrawElementsBaseVertex is 
interpreted as an offset within the buffer object measured in basic machine units.

So, the previous implementation was correct.

raysan5 added a commit that referenced this issue Jul 28, 2021
@rcorre
Copy link
Contributor Author

rcorre commented Jul 28, 2021

Great, thanks! Sorry for creating confusion.

Still, is it possible to avoid the undefined behavior (possibly by adding a separate function call for when the buffer and/or offset are 0)?

I think adding 0 to a null pointer is technically undefined, but even if it works, this prevents anyone from running a sanitized build of raylib (which might help catch bugs?)

@raysan5 raysan5 reopened this Jul 28, 2021
@raysan5
Copy link
Owner

raysan5 commented Jul 28, 2021

I'll see if it's possible to manage it in another way to avoid the undefined behaviour...

@raysan5
Copy link
Owner

raysan5 commented Jul 28, 2021

@rcorre I'm reviewing this issue but I'm afraid it's not easy to fix, if you read the official OpenGL implementation detail, if indices are mapped, then that pointer parameter is actually interpreted as an offset value:

While a non-zero buffer object is bound to the GL_ELEMENT_ARRAY_BUFFER target, 
the indices parameter of glDrawElements, glDrawElementsInstanced, glDrawElementsBaseVertex, 
glDrawRangeElements, glDrawRangeElementsBaseVertex, glMultiDrawElements, or glMultiDrawElementsBaseVertex is 
interpreted as an offset within the buffer object measured in basic machine units.

Actually, that's the reason current implementation passes the value as 0 instead of NULL, because it requires to be interpreted as an offset value instead of being understood as a pointer.

So, the problem is inherent to OpenGL library implementation, not on raylib side.

@raysan5 raysan5 closed this as completed Jul 28, 2021
@rcorre
Copy link
Contributor Author

rcorre commented Jul 29, 2021

@raysan5 the issue isn't passing NULL, it is performing pointer arithmetic on NULL, which does happen in the raylib codebase.

If a breaking change is ok, I think the easiest thing is to just remove the offset parameter:

diff --git a/src/models.c b/src/models.c
index 3d200d2a..0d13bb13 100644
--- a/src/models.c
+++ b/src/models.c
@@ -994,7 +994,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
                    material.maps[MATERIAL_MAP_DIFFUSE].color.b,
                    material.maps[MATERIAL_MAP_DIFFUSE].color.a);
 
-        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
+        if (mesh.indices != NULL) rlDrawVertexArrayElements(mesh.triangleCount*3, mesh.indices);
         else rlDrawVertexArray(0, mesh.vertexCount);
     rlPopMatrix();
 
@@ -1212,7 +1212,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
         }
         else    // Draw mesh
         {
-            if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
+            if (mesh.indices != NULL) rlDrawVertexArrayElements(mesh.triangleCount*3, 0);
             else rlDrawVertexArray(0, mesh.vertexCount);
         }
     }
diff --git a/src/rlgl.h b/src/rlgl.h
index 93227c2b..7aee2caa 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -569,7 +569,7 @@ RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool
 RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor);
 RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value
 RLAPI void rlDrawVertexArray(int offset, int count);
-RLAPI void rlDrawVertexArrayElements(int offset, int count, void *buffer);
+RLAPI void rlDrawVertexArrayElements(int count, void *buffer);
 RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances);
 RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances);
 
@@ -3119,9 +3119,9 @@ void rlDrawVertexArray(int offset, int count)
     glDrawArrays(GL_TRIANGLES, offset, count);
 }
 
-void rlDrawVertexArrayElements(int offset, int count, void *buffer)
+void rlDrawVertexArrayElements(int count, void *buffer)
 {
-    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset);
+    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer);
 }
 
 void rlDrawVertexArrayInstanced(int offset, int count, int instances)

The offset isn't used anywhere inside raylib, and I couldn't find any github projects using it either. Here's a search I generated with

gh api -X GET search/code -f q=rlDrawVertexArrayElements -H 'Accept: application/vnd.github.v3.text-match+json' | jq '.items[] | {repo: .repository.full_name, file: .name, text: .text_matches[] | .fragment}'

uses.json

@raysan5 raysan5 reopened this Jul 29, 2021
@raysan5
Copy link
Owner

raysan5 commented Jul 29, 2021

So, applying only the offset would be valid?

if (buffer == 0) glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, offset);
else glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset);

Note that raylib uses that offset internally for the batch rendering system, so, it could be useful for the users using rlgl.

@rcorre
Copy link
Contributor Author

rcorre commented Jul 30, 2021

@raysan5 that works -- I just tried it to confirm.

raysan5 added a commit that referenced this issue Jul 30, 2021
@raysan5 raysan5 closed this as completed Jul 30, 2021
raysan5 added a commit that referenced this issue Jul 30, 2021
@raysan5
Copy link
Owner

raysan5 commented Jul 30, 2021

Just reverted this change, now the warnings pop in the compiler. I'll leave it AS DESIGN, independently of what UBSAN thinks. Feel free to modify it in your fork.

@rcorre
Copy link
Contributor Author

rcorre commented Sep 5, 2023

@raysan5 do you remember why this had to be reverted? I couldn't find any info in the commit that reverted it.

rcorre pushed a commit to rcorre/raylib that referenced this issue Sep 5, 2023
Zig debug builds automatically enable ubsan.
As the fix for raysan5#1891 had to be reverted, debug builds using zig will crash like so:

```
Illegal instruction at address 0x3237d2
raylib/src/rlgl.h:3690:91: 0x3237d2 in rlDrawVertexArrayElements (/home/rcorre/src/raylib-zig-template/raylib/src/rcore.c)
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset);
```

This disables UBSAN when using zig to build raylib.
raysan5 pushed a commit that referenced this issue Sep 5, 2023
Zig debug builds automatically enable ubsan.
As the fix for #1891 had to be reverted, debug builds using zig will crash like so:

```
Illegal instruction at address 0x3237d2
raylib/src/rlgl.h:3690:91: 0x3237d2 in rlDrawVertexArrayElements (/home/rcorre/src/raylib-zig-template/raylib/src/rcore.c)
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset);
```

This disables UBSAN when using zig to build raylib.
@raysan5
Copy link
Owner

raysan5 commented Sep 5, 2023

@rcorre I don't remember exactly the reason (warnings on compiler side) but I can give another review. The point is that current implementation works and any attempt to change it could potentially break it.

@raysan5 raysan5 reopened this Sep 5, 2023
raysan5 added a commit that referenced this issue Sep 7, 2023
@raysan5
Copy link
Owner

raysan5 commented Sep 7, 2023

@rcorre I reviewed the function again, please, could you verify if it still complaints?

@raysan5 raysan5 closed this as completed Sep 7, 2023
@raysan5 raysan5 reopened this Sep 7, 2023
@rcorre
Copy link
Contributor Author

rcorre commented Sep 9, 2023

Yes, that fixed it @raysan5, thank you! Should we revert #3292?

@rcorre rcorre closed this as completed Sep 9, 2023
@raysan5
Copy link
Owner

raysan5 commented Sep 9, 2023

@rcorre probably yes, feel free to send a PR

rcorre pushed a commit to rcorre/raylib that referenced this issue Sep 9, 2023
This reverts commit a316f9e.

Issue raysan5#1891 was fixed again, so this is no longer needed.
raysan5 pushed a commit that referenced this issue Sep 9, 2023
This reverts commit a316f9e.

Issue #1891 was fixed again, so this is no longer needed.
Codom added a commit to Codom/raylib that referenced this issue Sep 17, 2023
Codom added a commit to Codom/raylib that referenced this issue Sep 17, 2023
raysan5 added a commit that referenced this issue Sep 17, 2023
* Prettified a comment

* fixed broken indentation caused by another commit.
the commit renamed a bool to int and broke indentation: 233cf39

* Changed 0.001 and 0.00001 to EPSILON
This commit is untested.
I don't know what consequences this has.
Since the commits that added these numbers were before epsilon was added,
I have assumed that epsilon could replace them.

* Prettied up indentation in a few places

* removed spacing around *, standardizing it.

* I may have gotten overboard with indentation

* removed a few useless parenthesis

* Added fortran-raylib

* Fix examples/others/rlgl_standalone.c compilation issue (#3242)

* Update BINDINGS.md

* Ignore unused return value of GetCodepointNext in GetCodepointCount (#3241)

* Ignore unused return value of GetCodepointNext in GetCodepointCount

Removes the last warning from non-external libraries when compiling with
the default build configuration on x64 Linux.

* Remove unnecessary void cast in GetCodepointCount

* Fix #3246

* Revert "Fix #3246"

This reverts commit e4dcbd5.

* Fix text_unicode.c example crashing (#3250)

* Fix text_unicode.c example crashing

* Adjust the text_unicode.c example crashing fix

* tweaks

* add build.zig options for individual modules (#3254)

* Add `IsKeyPressedRepeat` (desktop only) (#3245)

Since the key pressed are handle by comparing current vs previous
state (ie frame), a special way is needed to handle key repeats.

* Reviewed `IsKeyPressedRepeat()` #3248

* Update rcore.c (#3255)

* Match CMakeOptions.txt options default values (#3258)

* Fix SetClipboardText for web (#3257)

* [Image] Validate that ImageDrawRectangleRec is drawing entirely inside the image (#3264)

* Add a function to clone a sound and share data with another sound.

* rename items based on feedback

* PR Feedback, use custom unload for sound alias, not variant of normal sound unloading

* sound_multi example

* Validate that image rect drawing is inside the image so we don't overflow a buffer

* remove files that should not have been added.

* remove changes that should not have been

* revert

* adsfasdfsdfsdf

* Add Vector3 Projecting and Rejection to Raymath (#3263)

* Update raymath.h

* formatting

* [Feature] IsKey... safety checks and more (#3256)

* [Feature] Add GetKeyRepeat

* Update rcore.c

* Simpler design, only one repeat per frame

* Update config.h

* Update rcore.c

* Add KEYBOARD_KEYS_MASK

* Update config.h

* reversions

* Update rcore.c

* Update rcore.c

* change docs

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update raylib.h

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Update rcore.c

* Fix bug where default shaders was not linking. (#3261)

* Formating review

* Add missing cmake options (#3267)

* Fix CMake extraneous -lglfw (#3266)

Closes #3265.

The problem: LIBS_PRIVATE is a list of library names (used by pkg-config), but the shared library of the same name doesn't always exist.

* Fix example/models/models_loading_gltf.c controls (#3268)

* Fix example/models/models_loading_m3d.c controls (#3269)

* Remove e from secondes (#3270)

* Fix example/audio/audio_module_player.c help instructions and small bug (#3272)

* Fix example/audio/audio_module_player.c help instructions and small bug

* Update example/audio/audio_module_player.png screenshot

* Use type name instead of valid specifier

long long --> long long int

* REVIEWED: `GetFileLength()`, added comment #3262

* Update examples/models/models_loading_gltf.png;m3d.png screenshots (#3273)

* Remove a duplicated screenshot and add missing one (#3275)

* Add examples/shaders/shaders_lightmap.c to Makefiles (#3276)

* Fix examples/others/easings_testbed.c help instructions and small tweak (#3277)

* Fix examples/shaders/shaders_texture_outline.c help instructions (#3278)

* Fix examples/shapes/shapes_collision_area.c help instructions (#3279)

* RENAMED: LoadFont*() parameter names for consistency and coherence

* Fix uninitialized thread-locals in stbi #3282 (#3283)

* REVIEWED: Added `SetTextLineSpacing()` to multiline examples

* REVIEWED: Data size type consistency between functions #3168

* Some tweaks

* Use internal default allocators, instead of user-exposed ones

* Added rudimentary SVG support. (#2738)

* Added rudimentary SVG support. Added 2 functions ImageLoadSvg and ImageLoadSvgWithSize.

* Added an example on how to use ImageLoadSvgWithSize and adjusted Makefiles accordingly.

* Added actual correct example file.

* Reviewed the code to keep the raylib coding conventions in mind.
Moved the LoadImageSvg() code into LoadImage() guarded by SUPPORT_FILEFORMAT_SVG.
Renamed LoadImageSvgWithSize() to LoadImageSvg().
Added a LoadImageSvgFromString() function to parse the loaded SVG into an actual image. This does the bulk of the work.

* Fixed typo.

---------

Co-authored-by: Ray <[email protected]>

* REVIEWED: `LoadImageSvg()`

* REVIEWED: `LoadImageSvg()`

* Add SUPPORT_FILEFORMAT_SVG to cmake (#3284)

* Fix examples/textures/textures_fog_of_war.c help instructions (#3285)

* Fix examples/textures/textures_image_rotate.c help instructions (#3286)

* Update rtextures.c

* Fix #3247

* Update config.h

* Fix #3293

* Disable UBSAN in zig builds. (#3292)

Zig debug builds automatically enable ubsan.
As the fix for #1891 had to be reverted, debug builds using zig will crash like so:

```
Illegal instruction at address 0x3237d2
raylib/src/rlgl.h:3690:91: 0x3237d2 in rlDrawVertexArrayElements (/home/rcorre/src/raylib-zig-template/raylib/src/rcore.c)
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset);
```

This disables UBSAN when using zig to build raylib.

* Update README.md (#3290)

specially -> especially

* Update cmake SUPPORT_FILEFORMAT_SVG default value (#3291)

* Mouse offset and scaling must be considered also on web!

* Update rcore.c

* Update Makefile : clean raygui.c & physac.c (#3296)

* Remove PLATFORM_RPI (#3232)

* Remove PLATFORM_RPI

* remove build artifacts

---------

Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: Ray <[email protected]>

* Review to avoid UBSAN complaining #1891

* added raylib-raku to bindings (#3299)

* examples: core: adds 2D camera two player split screen (#3298)

* Reviewed examples for consistency

* Update rtext.c

* Some code restructuring for input functions, consistency review

* Remove unneeded #if (#3301)

Co-authored-by: MichaelFiber <[email protected]>

* Revert "Disable UBSAN in zig builds. (#3292)" (#3303)

This reverts commit a316f9e.

Issue #1891 was fixed again, so this is no longer needed.

* rtextures: Fix ImageDraw() source clipping when drawing beyond top left (#3306)

* REVIEWED: `TextToPascal()` issue when first char is uppercase

* Implement FLAG_WINDOW_RESIZABLE for web (#3305)

Fixes #3231

* Update BINDINGS.md (#3307)

Fix Kaylib binding. Reroute to a new repository.
Binding renamed.

* Update webassembly.yml

* Add claw-raylib to BINDINGS.md (#3310)

* Add SetWindowMaxSize for desktop and web (#3309)

* Add SetWindowMaxSize for desktop and web

* Remove SizeInt and respective adjustments

* Update rtextures.c

* Reviewed parameters for consistency

* Rename windowM* to screenM* (#3312)

* Update BINDINGS.md (#3317)

Update TurboRaylib bindings

* Update rmodels.c

* Update BINDINGS.md with vaiorabbit/raylib-bindings (#3318)

* fixed spelling mistake

* put back parenthesis

* reverted major allignment changes

* reverted parser output changes

* reverted one more indentation change

---------

Co-authored-by: Brian-E <[email protected]>
Co-authored-by: Ray <[email protected]>
Co-authored-by: ubkp <[email protected]>
Co-authored-by: ashn <[email protected]>
Co-authored-by: actondev (Christos) <[email protected]>
Co-authored-by: vitopigno <[email protected]>
Co-authored-by: Asdqwe <[email protected]>
Co-authored-by: Jeffery Myers <[email protected]>
Co-authored-by: Ethan Simpson <[email protected]>
Co-authored-by: Nickolas McDonald <[email protected]>
Co-authored-by: Branimir Ričko <[email protected]>
Co-authored-by: iacore <[email protected]>
Co-authored-by: Ethan Conneely <[email protected]>
Co-authored-by: Johannes Barthelmes <[email protected]>
Co-authored-by: bXi <[email protected]>
Co-authored-by: Ryan Roden-Corrent <[email protected]>
Co-authored-by: Ikko Eltociear Ashimine <[email protected]>
Co-authored-by: SuperUserNameMan <[email protected]>
Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: MichaelFiber <[email protected]>
Co-authored-by: Dan Vu <[email protected]>
Co-authored-by: Gabriel dos Santos Sanches <[email protected]>
Co-authored-by: Rob Loach <[email protected]>
Co-authored-by: Peter0x44 <[email protected]>
Co-authored-by: Kenta <[email protected]>
Co-authored-by: bohonghuang <[email protected]>
Co-authored-by: turborium <[email protected]>
Co-authored-by: Wilson Silva <[email protected]>
Codom added a commit to Codom/raylib that referenced this issue Sep 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants