mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-09-16 07:14:36 +00:00
Compare commits
5 Commits
v3_c
...
backup/rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7120431da6 | ||
|
|
3c25af4a57 | ||
|
|
64513ea069 | ||
|
|
75081ef5f0 | ||
|
|
544290f60d |
92
.github/instructions/copilot-instructions.md
vendored
92
.github/instructions/copilot-instructions.md
vendored
@@ -1,92 +0,0 @@
|
|||||||
# Copilot Review Instructions for TinyGLTF
|
|
||||||
|
|
||||||
This document provides guidelines for reviewing code changes in the TinyGLTF repository.
|
|
||||||
|
|
||||||
## Memory Safety
|
|
||||||
|
|
||||||
- **Buffer Overflows**: Check for proper bounds checking when accessing arrays, vectors, and buffers. Verify that buffer sizes are validated before read/write operations.
|
|
||||||
- **Null Pointer Dereferences**: Ensure all pointers are checked for null before dereferencing, especially when handling optional glTF fields.
|
|
||||||
- **Memory Leaks**: Verify proper resource management, including RAII patterns for file handles, image data, and dynamically allocated memory.
|
|
||||||
- **Use-After-Free**: Check for proper lifetime management of objects, especially when dealing with callbacks and asynchronous operations.
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
- **File I/O**: Verify that all file operations have proper error checking and meaningful error messages.
|
|
||||||
- **JSON Parsing**: Ensure JSON parsing errors are caught and reported with helpful context about the location and nature of the error.
|
|
||||||
- **Resource Loading**: Check that failures in loading images, buffers, and other resources are properly handled and don't cause crashes.
|
|
||||||
- **Error Propagation**: Verify that errors are properly propagated through the call stack with appropriate error messages.
|
|
||||||
|
|
||||||
## glTF 2.0 Specification Compliance
|
|
||||||
|
|
||||||
- **Required Fields**: Ensure all required glTF fields are validated and present.
|
|
||||||
- **Data Types**: Verify that data types match the glTF specification (e.g., component types, accessor types).
|
|
||||||
- **Constraints**: Check that glTF constraints are enforced (e.g., valid ranges for enums, buffer stride requirements).
|
|
||||||
- **Extensions**: Verify proper handling of glTF extensions and that unknown extensions are handled gracefully.
|
|
||||||
- **Validation**: Ensure new features align with the glTF 2.0 specification from the Khronos Group.
|
|
||||||
|
|
||||||
## Cross-Platform Compatibility
|
|
||||||
|
|
||||||
- **Windows**: Check for proper handling of Windows-specific issues (path separators, line endings, file operations).
|
|
||||||
- **Linux**: Verify compatibility with various Linux distributions and compilers (GCC, Clang).
|
|
||||||
- **macOS**: Ensure macOS-specific considerations are addressed (case-sensitive filesystems, Clang compatibility).
|
|
||||||
- **Mobile Platforms**: Consider Android and iOS compatibility where applicable.
|
|
||||||
- **Endianness**: Verify proper handling of byte order when reading binary data.
|
|
||||||
- **Compiler Compatibility**: Ensure code compiles with C++11 standard and supported compilers (MSVC, GCC, Clang).
|
|
||||||
|
|
||||||
## Edge Cases in glTF Parsing
|
|
||||||
|
|
||||||
- **Empty/Minimal Files**: Verify handling of minimal valid glTF files.
|
|
||||||
- **Large Files**: Check for proper handling of large glTF files and buffers without memory exhaustion.
|
|
||||||
- **Malformed Data**: Ensure graceful handling of malformed or invalid glTF data.
|
|
||||||
- **Missing Optional Fields**: Verify correct behavior when optional glTF fields are absent.
|
|
||||||
- **Edge Values**: Check handling of boundary values (e.g., maximum buffer sizes, extreme floating-point values).
|
|
||||||
- **Base64 Encoding**: Verify proper handling of base64-encoded data URIs and invalid encodings.
|
|
||||||
|
|
||||||
## Backwards Compatibility
|
|
||||||
|
|
||||||
- **API Changes**: Ensure public API changes maintain backwards compatibility or are properly deprecated.
|
|
||||||
- **Breaking Changes**: Flag any breaking changes for major version updates and document migration paths.
|
|
||||||
- **Binary Compatibility**: Consider ABI stability for header-only library changes.
|
|
||||||
- **Default Behavior**: Verify that default behavior of existing functionality remains unchanged.
|
|
||||||
|
|
||||||
## Performance Considerations
|
|
||||||
|
|
||||||
- **Parsing Performance**: Check for unnecessary copies, redundant allocations, and inefficient algorithms in parsing logic.
|
|
||||||
- **Memory Usage**: Verify efficient memory usage, especially when loading large glTF files.
|
|
||||||
- **I/O Operations**: Ensure efficient file reading and minimize unnecessary disk access.
|
|
||||||
- **String Operations**: Check for efficient string handling (use of string_view, move semantics).
|
|
||||||
- **STL Usage**: Verify appropriate use of STL containers and algorithms.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- **Public API**: Ensure all public functions, classes, and methods have clear documentation comments.
|
|
||||||
- **Parameters**: Verify that function parameters are documented, including expected ranges and constraints.
|
|
||||||
- **Return Values**: Document return values and possible error conditions.
|
|
||||||
- **Examples**: Check that complex features include usage examples.
|
|
||||||
- **Changelog**: Verify that significant changes are documented in release notes or changelog.
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
- **Test Coverage**: Ensure new features include appropriate unit tests or integration tests.
|
|
||||||
- **Edge Cases**: Verify that tests cover edge cases and error conditions.
|
|
||||||
- **Cross-Platform Tests**: Check that tests run on all supported platforms.
|
|
||||||
- **Regression Tests**: Ensure bug fixes include regression tests to prevent recurrence.
|
|
||||||
- **Sample Files**: Verify that changes are tested with various valid and invalid glTF sample files.
|
|
||||||
|
|
||||||
## Code Style Consistency
|
|
||||||
|
|
||||||
- **Header-Only Pattern**: Maintain the header-only library structure.
|
|
||||||
- **Naming Conventions**: Follow existing naming conventions (CamelCase for types, snake_case for functions where applicable).
|
|
||||||
- **Formatting**: Adhere to the existing code formatting style (check `.clang-format` if available).
|
|
||||||
- **Include Guards**: Verify proper include guards and header organization.
|
|
||||||
- **Namespace Usage**: Ensure proper use of the `tinygltf` namespace.
|
|
||||||
- **Comments**: Maintain consistent comment style with existing code.
|
|
||||||
- **C++11 Compliance**: Verify that code uses C++11 features appropriately and doesn't require newer standards unless specified.
|
|
||||||
|
|
||||||
## Additional Considerations
|
|
||||||
|
|
||||||
- **Third-Party Dependencies**: Minimize new dependencies; prefer existing dependencies (json.hpp, stb_image).
|
|
||||||
- **Warnings**: Ensure code compiles without warnings on supported compilers.
|
|
||||||
- **const Correctness**: Verify proper use of const for parameters and methods.
|
|
||||||
- **RAII**: Prefer RAII patterns for resource management over manual cleanup.
|
|
||||||
- **noexcept**: Use noexcept appropriately for move constructors and move assignment operators.
|
|
||||||
72
.github/workflows/codeql-analysis.yml
vendored
72
.github/workflows/codeql-analysis.yml
vendored
@@ -1,72 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ "master" ]
|
|
||||||
schedule:
|
|
||||||
- cron: '21 20 * * 5'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'cpp', 'python' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v3
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
|
|
||||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
||||||
# queries: security-extended,security-and-quality
|
|
||||||
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v3
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
|
|
||||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
|
||||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
|
||||||
|
|
||||||
# - run: |
|
|
||||||
# echo "Run, Build Application using script"
|
|
||||||
# ./location_of_script_within_repo/buildscript.sh
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v3
|
|
||||||
17
README.md
17
README.md
@@ -19,7 +19,7 @@ v3 is a ground-up rewrite with a C-centric, low-overhead design:
|
|||||||
- **No RTTI, no exceptions required** — suitable for embedded and game-engine use.
|
- **No RTTI, no exceptions required** — suitable for embedded and game-engine use.
|
||||||
- **Opt-in filesystem and image I/O** — `TINYGLTF3_ENABLE_FS` / `TINYGLTF3_ENABLE_STB_IMAGE` are off by default; you control when and how assets are loaded.
|
- **Opt-in filesystem and image I/O** — `TINYGLTF3_ENABLE_FS` / `TINYGLTF3_ENABLE_STB_IMAGE` are off by default; you control when and how assets are loaded.
|
||||||
- **C++20 coroutine facade** (optional, auto-detected). C17/C++17 default.
|
- **C++20 coroutine facade** (optional, auto-detected). C17/C++17 default.
|
||||||
- **Hardened against untrusted input** — URI sanitization, post-parse index-bounds validation (default-on, opt-out via `tg3_parse_options.validate_indices = 0`), strict numeric range checks; exercised by a libFuzzer harness and by a cross-version verifier that compares parsed output against the v1 C++ reference loader. See *Security model* below and the `Security Considerations` block at the top of `tiny_gltf_v3.h`.
|
- **Hardened against untrusted input** — URI sanitization, post-parse index-bounds validation (default-on, opt-out via `tg3_parse_options.validate_indices = 0`), strict numeric range checks; exercised by a libFuzzer harness and by a cross-version verifier that compares parsed output against the v1 C++ reference loader. See the `Security Considerations` block at the top of `tiny_gltf_v3.h`.
|
||||||
|
|
||||||
### Quick start (v3)
|
### Quick start (v3)
|
||||||
|
|
||||||
@@ -55,21 +55,6 @@ tg3_model_free(&model);
|
|||||||
tg3_error_stack_free(&errors);
|
tg3_error_stack_free(&errors);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Security model (v3 C runtime)
|
|
||||||
|
|
||||||
The v3 C runtime is built for processing **untrusted glTF/GLB input** (server-side asset pipelines, user uploads, etc.) and ships hardened by default:
|
|
||||||
|
|
||||||
- **URI sanitization** — external buffer/image URIs are rejected before any filesystem call if they are empty, contain NUL bytes, begin with `/` or `\`, look like a Windows drive prefix (`X:`), or contain a `..` segment. Production callers SHOULD still provide a custom `tg3_fs_callbacks.read_file` that confines reads to a known directory (e.g. via `openat` plus a `realpath` prefix check) when the input is attacker-controlled.
|
|
||||||
- **Index bounds validation** — every `int32_t` index field populated from JSON (accessor.bufferView, primitive.indices/material/attributes, scene.nodes[], skin.joints[], animation channel/sampler refs, KHR_audio + MSFT_lod refs, …) is checked after the structural parse. Out-of-range indices produce `TG3_ERR_INVALID_INDEX`. Default `tg3_parse_options.validate_indices = 1`; set to `0` only when you need raw round-trip and have your own validator.
|
|
||||||
- **Buffer/accessor range validation** — declared buffer lengths, bufferView ranges, accessor element spans, sparse accessor spans, component types, and overflow-prone size math are checked before returning a model.
|
|
||||||
- **Strict numeric range checks** — JSON numbers feeding integer fields go through finite/round-trip-validated coercion (`tg3__json_number_to_int32` / `_uint64`). `byteStride` is restricted to 0 or [4, 252].
|
|
||||||
- **Memory budget** — the arena and C JSON parser enforce `TINYGLTF3_MAX_MEMORY_BYTES` by default; `max_single_alloc` and `TINYGLTF3_MAX_STRING_LENGTH` bound individual allocation and string size.
|
|
||||||
- **Opt-in fast paths** — `skip_extras_values` avoids materializing `extras` and unknown extension value trees, and `borrow_input_buffers` lets GLB buffer spans reference caller-owned input bytes instead of copying the BIN chunk.
|
|
||||||
- **Image decoding off by default** — the parser does not decode image bytes; use `tg3_parse_options.images_as_is = 1` to skip any decoder entirely when handling untrusted input.
|
|
||||||
- **Error message lifetime** — error strings on `tg3_error_stack` are arena-allocated and remain valid until `tg3_model_free()`. Read or copy them BEFORE freeing the model.
|
|
||||||
|
|
||||||
See the `Security Considerations` block at the top of `tiny_gltf_v3.h` for the authoritative threat-model summary.
|
|
||||||
|
|
||||||
### Testing & verification
|
### Testing & verification
|
||||||
|
|
||||||
The v3 C runtime ships with three layers of automated coverage:
|
The v3 C runtime ships with three layers of automated coverage:
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
This project manages CVE assignments exclusively through
|
|
||||||
GitHub Security Advisories.
|
|
||||||
BIN
tests/tester_v3_c
Executable file
BIN
tests/tester_v3_c
Executable file
Binary file not shown.
BIN
tests/tester_v3_c_v1port
Executable file
BIN
tests/tester_v3_c_v1port
Executable file
Binary file not shown.
BIN
tests/tester_v3_freestanding
Executable file
BIN
tests/tester_v3_freestanding
Executable file
Binary file not shown.
BIN
tests/tester_v3_json_c
Executable file
BIN
tests/tester_v3_json_c
Executable file
Binary file not shown.
@@ -7059,7 +7059,11 @@ static void SerializeNumberProperty(const std::string &key, T number,
|
|||||||
detail::JsonAddMember(obj, key.c_str(), detail::json(number));
|
detail::JsonAddMember(obj, key.c_str(), detail::json(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
#if defined(TINYGLTF_USE_RAPIDJSON) || defined(TINYGLTF_USE_CUSTOM_JSON)
|
||||||
|
// size_t needs an explicit cast to uint64_t: on platforms where size_t is
|
||||||
|
// neither int64_t nor uint64_t (e.g. macOS ARM64 where it is unsigned long,
|
||||||
|
// or 32-bit targets where it is unsigned int) constructing detail::json
|
||||||
|
// directly from a size_t is an ambiguous overload.
|
||||||
template <>
|
template <>
|
||||||
void SerializeNumberProperty(const std::string &key, size_t number,
|
void SerializeNumberProperty(const std::string &key, size_t number,
|
||||||
detail::json &obj) {
|
detail::json &obj) {
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ static size_t tg3json__itoa(int64_t value, char *buf) {
|
|||||||
return (size_t)(p - buf);
|
return (size_t)(p - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !TG3JSON_USE_STDLIB_FPCONV
|
||||||
static size_t tg3json__utoa(uint64_t value, char *buf) {
|
static size_t tg3json__utoa(uint64_t value, char *buf) {
|
||||||
char tmp[32];
|
char tmp[32];
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@@ -267,6 +268,7 @@ static size_t tg3json__utoa(uint64_t value, char *buf) {
|
|||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
#endif /* !TG3JSON_USE_STDLIB_FPCONV */
|
||||||
|
|
||||||
static uint64_t tg3json__double_bits(double v) {
|
static uint64_t tg3json__double_bits(double v) {
|
||||||
uint64_t bits = 0;
|
uint64_t bits = 0;
|
||||||
@@ -433,6 +435,7 @@ static int tg3json__parse_f64_c(const char *start, const char *end, double *out)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !TG3JSON_USE_STDLIB_FPCONV
|
||||||
static char *tg3json__write_exp(char *p, int exp10) {
|
static char *tg3json__write_exp(char *p, int exp10) {
|
||||||
char tmp[16];
|
char tmp[16];
|
||||||
size_t n;
|
size_t n;
|
||||||
@@ -479,6 +482,7 @@ static char *tg3json__format_decimal_digits(char *out, const char *digits,
|
|||||||
for (i = 0; i < ndigits; ++i) *p++ = digits[i];
|
for (i = 0; i < ndigits; ++i) *p++ = digits[i];
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
#endif /* !TG3JSON_USE_STDLIB_FPCONV */
|
||||||
|
|
||||||
static int tg3json__same_f64(double a, double b) {
|
static int tg3json__same_f64(double a, double b) {
|
||||||
return tg3json__double_bits(a) == tg3json__double_bits(b);
|
return tg3json__double_bits(a) == tg3json__double_bits(b);
|
||||||
@@ -579,6 +583,7 @@ static char *tg3json__dtoa_c(double value, char *buf) {
|
|||||||
uint64_t bits = tg3json__double_bits(value);
|
uint64_t bits = tg3json__double_bits(value);
|
||||||
int negative = (int)(bits >> 63);
|
int negative = (int)(bits >> 63);
|
||||||
uint64_t abits = bits & 0x7fffffffffffffffULL;
|
uint64_t abits = bits & 0x7fffffffffffffffULL;
|
||||||
|
#if !TG3JSON_USE_STDLIB_FPCONV
|
||||||
long double x;
|
long double x;
|
||||||
int dec_e = 0;
|
int dec_e = 0;
|
||||||
char digits[24];
|
char digits[24];
|
||||||
@@ -586,6 +591,7 @@ static char *tg3json__dtoa_c(double value, char *buf) {
|
|||||||
int i;
|
int i;
|
||||||
char best[80];
|
char best[80];
|
||||||
size_t best_len;
|
size_t best_len;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (tg3json__is_nan_bits(bits)) {
|
if (tg3json__is_nan_bits(bits)) {
|
||||||
TINYGLTF_JSON_MEMCPY(buf, "nan", 3);
|
TINYGLTF_JSON_MEMCPY(buf, "nan", 3);
|
||||||
@@ -644,7 +650,7 @@ static char *tg3json__dtoa_c(double value, char *buf) {
|
|||||||
TINYGLTF_JSON_MEMCPY(buf, shortest, TINYGLTF_JSON_STRLEN(shortest));
|
TINYGLTF_JSON_MEMCPY(buf, shortest, TINYGLTF_JSON_STRLEN(shortest));
|
||||||
return buf + TINYGLTF_JSON_STRLEN(shortest);
|
return buf + TINYGLTF_JSON_STRLEN(shortest);
|
||||||
}
|
}
|
||||||
#endif
|
#else
|
||||||
|
|
||||||
x = negative ? -(long double)value : (long double)value;
|
x = negative ? -(long double)value : (long double)value;
|
||||||
while (x >= 1.0e16L) {
|
while (x >= 1.0e16L) {
|
||||||
@@ -708,6 +714,7 @@ static char *tg3json__dtoa_c(double value, char *buf) {
|
|||||||
}
|
}
|
||||||
TINYGLTF_JSON_MEMCPY(buf, best, best_len);
|
TINYGLTF_JSON_MEMCPY(buf, best, best_len);
|
||||||
return buf + best_len;
|
return buf + best_len;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct tg3json__parser {
|
typedef struct tg3json__parser {
|
||||||
|
|||||||
Reference in New Issue
Block a user