eb948bc5a8
My friends, gather around as I learned something about the C standard that is horrifying and may keep you, dear reader, up at night. My journey began trying to fix something entirely unrelated and not wanting to wait for ubsan builds when changing a testcase. So me, in my infinite naivete just built the engine with tests=yes, but optimizations turned on. This resulted in a segfault on "[Audio][AudioStreamWAV] Save empty file". Well, then, I thought. Lets built with asan then and find out where this happens! Would it surprise you, my fellow traveler, that the results were that no such crash occurred? Thus, to the debugger I go! Fearless, with great optimism. Where I find that through many an indirection the crash came because, somehow, CowData::_unref() was getting called with a _ptr set to 0x1. This can of course only end in tears. Or segmentation faults as we try to read an atomic variable at the somewhat inconveniently situated address at 0xfffffffffffffff0. So I went and looked at the likely culprit, blaming many an innocent recent change along the way. I shall spare you the falsly accused. But if for some reason you slept poorly last night, I can assure you that the voodoo dolls have been put away and will not be harmed further. So in AudioStreamWAV::get_data() we go, where we find a perfectly reasonable function! It checks to see whether or not its data is empty, and if it is not it will resize a temporary Vector to have data_bytes of space, after which it will do a perfectly pedestrian memcpy() and all is well in the world. Or so it seems! After many an hour of despair and disassembly I, at last, decided to look at where the data gets set! A breakthrough! Because of the padding data is never empty! So the code always runs! Eureka! One would think. But then, foolishly, I looked into the get_data() function one more. My mortal enemy was staring me in the face, laughing. Because it did not care about this. Sure, the check was worthless but still... What are we left with. At this point I could feel the method mocking me. "I resize the vector to 0, I then memcpy zero bytes into it." It said, DARING me to object to this state of affairs. And yet, if I changed the function to check for "data_bytes" rather than data.is_empty() no crashes. Was this a compiler bug? Am I losing my mind? But then... I remembered the mantra of the wise compiler druids... "It Is Not A Compiler Bug". But what then! The bug does not happen when memory is being watched! Valgrind agreed that while accessing the SafeRefCount at 0xfffffffffffffff0 was incredibly rude, it did not inform me of anything else untoward happening. So I read the memcpy() manpage... nothing... I read the the memcpy() posix spec... nothing. Finally, in despair and because I had nothing left to lose... The ISO C language specification. As I was reading, I could hear AudioStreamWAV::get_data() cackling, knowing that its time was up, but proud of the madness it caused in my soul. Knowing I would never be the same. The behavior is undefined if either dest or src is an invalid or null pointer. So... Here I stand before you, a broken person. But one richer in knowledge. I write you this from the depths of madness in the hopes that you, dear reader, can be spared this ordeal. May god have mercy on our souls. We trigger the following sequence of events: * memcpy(null, null, 0) is UB, thus dest and src cannot be null * we inline the calls to the ctor and dtor * now we have a function that does something that "proves" dest cannot be null * we inline cowdata::_unref() which does a null check, on something that the compiler just convinced itself cannot be null * the compiler removes the dead code branch where _ptr == nullptr * we start to do pointer arithmetic on a nullptr and get send to uninitialized memory. Co-Authored-By: Jason Beckmann <jasonabeckmann@gmail.com> |
||
---|---|---|
.github | ||
core | ||
doc | ||
drivers | ||
editor | ||
main | ||
misc | ||
modules | ||
platform | ||
scene | ||
servers | ||
tests | ||
thirdparty | ||
.clang-format | ||
.clang-tidy | ||
.editorconfig | ||
.git-blame-ignore-revs | ||
.gitattributes | ||
.gitignore | ||
.mailmap | ||
.pre-commit-config.yaml | ||
AUTHORS.md | ||
CHANGELOG.md | ||
CONTRIBUTING.md | ||
COPYRIGHT.txt | ||
DONORS.md | ||
gles3_builders.py | ||
glsl_builders.py | ||
godot.manifest | ||
icon_outlined.png | ||
icon_outlined.svg | ||
icon.png | ||
icon.svg | ||
LICENSE.txt | ||
LOGO_LICENSE.txt | ||
logo_outlined.png | ||
logo_outlined.svg | ||
logo.png | ||
logo.svg | ||
methods.py | ||
platform_methods.py | ||
pyproject.toml | ||
README.md | ||
SConstruct | ||
scu_builders.py | ||
version.py |
Godot Engine
2D and 3D cross-platform game engine
Godot Engine is a feature-packed, cross-platform game engine to create 2D and 3D games from a unified interface. It provides a comprehensive set of common tools, so that users can focus on making games without having to reinvent the wheel. Games can be exported with one click to a number of platforms, including the major desktop platforms (Linux, macOS, Windows), mobile platforms (Android, iOS), as well as Web-based platforms and consoles.
Free, open source and community-driven
Godot is completely free and open source under the very permissive MIT license. No strings attached, no royalties, nothing. The users' games are theirs, down to the last line of engine code. Godot's development is fully independent and community-driven, empowering users to help shape their engine to match their expectations. It is supported by the Godot Foundation not-for-profit.
Before being open sourced in February 2014, Godot had been developed by Juan Linietsky and Ariel Manzur (both still maintaining the project) for several years as an in-house engine, used to publish several work-for-hire titles.
Getting the engine
Binary downloads
Official binaries for the Godot editor and the export templates can be found on the Godot website.
Compiling from source
See the official docs for compilation instructions for every supported platform.
Community and contributing
Godot is not only an engine but an ever-growing community of users and engine developers. The main community channels are listed on the homepage.
The best way to get in touch with the core engine developers is to join the Godot Contributors Chat.
To get started contributing to the project, see the contributing guide. This document also includes guidelines for reporting bugs.
Documentation and demos
The official documentation is hosted on Read the Docs. It is maintained by the Godot community in its own GitHub repository.
The class reference is also accessible from the Godot editor.
We also maintain official demos in their own GitHub repository as well as a list of awesome Godot community resources.
There are also a number of other learning resources provided by the community, such as text and video tutorials, demos, etc. Consult the community channels for more information.