mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Fix timeSamples pprint for array types and add bounds checking
- Fix move constructor/assignment operator to transfer value array storage fields (_value_array_storage, _value_array_refs, _use_value_array) - Fix copy constructor/assignment operator for value array storage fields - Add bounds checking for blocked[] and offsets[] array access in pprint - Strip TYPE_ID_1D_ARRAY_BIT before type lookup in print_pod_value_dispatch and get_pod_type_size to handle array element types correctly - Add handler for value array storage path in get_samples() - Set _use_pod=false when using value array storage This fixes the "Unknown type_id: 1048618" error when printing array-typed timeSamples (e.g., color3f[]) and prevents heap-buffer-overflow when printing timeSamples with None values. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
15
scripts/bootstrap-cmake-linux-asan.sh
Executable file
15
scripts/bootstrap-cmake-linux-asan.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
curdir=`pwd`
|
||||
|
||||
builddir=${curdir}/build_asan
|
||||
|
||||
rm -rf ${builddir}
|
||||
mkdir ${builddir}
|
||||
|
||||
# with lld linker
|
||||
# -DCMAKE_TOOLCHAIN_FILE=cmake/lld-linux.toolchain.cmake
|
||||
|
||||
cd ${builddir} && CXX=clang++ CC=clang cmake \
|
||||
-DSANITIZE_ADDRESS=1 \
|
||||
-DCMAKE_VERBOSE_MAKEFILE=1 \
|
||||
..
|
||||
|
||||
@@ -311,6 +311,9 @@ void print_vector<uint8_t, 4>(OutputAdapter& out, const uint8_t* data) {
|
||||
void print_pod_value_dispatch(OutputAdapter& out, const uint8_t* data, uint32_t type_id) {
|
||||
using namespace value;
|
||||
|
||||
// Strip array bit - we're printing a single element
|
||||
type_id = type_id & (~TYPE_ID_1D_ARRAY_BIT);
|
||||
|
||||
switch (type_id) {
|
||||
DISPATCH_POD_TYPE(TYPE_ID_BOOL, bool, print_type)
|
||||
DISPATCH_POD_TYPE(TYPE_ID_CHAR, char, print_type)
|
||||
@@ -1490,6 +1493,9 @@ void pprint_pod_value_by_type(StreamWriter& writer, const uint8_t* data, uint32_
|
||||
size_t get_pod_type_size(uint32_t type_id) {
|
||||
using namespace value;
|
||||
|
||||
// Strip array bit - we want the element size
|
||||
type_id = type_id & (~TYPE_ID_1D_ARRAY_BIT);
|
||||
|
||||
switch (type_id) {
|
||||
case TYPE_ID_BOOL:
|
||||
return sizeof(bool);
|
||||
@@ -2326,10 +2332,6 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
|
||||
const auto& offsets = samples.get_offsets();
|
||||
const auto& array_counts = samples.get_array_counts();
|
||||
|
||||
//TUSDZ_LOG_I("times.size " << times.size());
|
||||
//TUSDZ_LOG_I("blocked.size " << blocked.size());
|
||||
//TUSDZ_LOG_I("values.size " << values.size());
|
||||
|
||||
// Write samples - handle offset table if present
|
||||
if (!offsets.empty()) {
|
||||
|
||||
@@ -2340,7 +2342,11 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
|
||||
writer.write(times[i]);
|
||||
writer.write(": ");
|
||||
|
||||
if (blocked[i] || offsets[i] == SIZE_MAX) {
|
||||
// Check blocked array bounds before accessing
|
||||
bool is_blocked = (i < blocked.size()) ? blocked[i] : false;
|
||||
// Check offsets bounds as well - treat out-of-bounds as None
|
||||
bool offset_is_none = (i >= offsets.size()) || (offsets[i] == SIZE_MAX);
|
||||
if (is_blocked || offset_is_none) {
|
||||
writer.write("None");
|
||||
} else {
|
||||
// Resolve offset (may be encoded with dedup/array flags) and get resolved index
|
||||
@@ -2374,6 +2380,18 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
|
||||
}
|
||||
} else {
|
||||
// Legacy: blocked values still counted in offset calculation
|
||||
// Handle case where values is empty but times is not
|
||||
if (values.empty() && !times.empty()) {
|
||||
for (size_t i = 0; i < times.size(); ++i) {
|
||||
writer.write(pprint::Indent(indent + 1));
|
||||
writer.write(times[i]);
|
||||
writer.write(": /* empty value data */");
|
||||
if (i < times.size() - 1) {
|
||||
writer.write(",");
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
} else {
|
||||
size_t value_offset = 0;
|
||||
for (size_t i = 0; i < times.size(); ++i) {
|
||||
//TUSDZ_LOG_I("times[" << i << "] = " << times[i]);
|
||||
@@ -2381,7 +2399,9 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
|
||||
writer.write(times[i]);
|
||||
writer.write(": ");
|
||||
|
||||
if (blocked[i]) {
|
||||
// Check blocked array bounds before accessing
|
||||
bool is_blocked = (i < blocked.size()) ? blocked[i] : false;
|
||||
if (is_blocked) {
|
||||
writer.write("None");
|
||||
} else {
|
||||
// Get pointer to value data
|
||||
@@ -2407,6 +2427,7 @@ void pprint_timesamples(StreamWriter& writer, const value::TimeSamples& samples,
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
} // end else for values.empty() check
|
||||
}
|
||||
} else {
|
||||
// Non-POD path: use regular samples
|
||||
|
||||
@@ -1600,8 +1600,11 @@ TimeSamples::TimeSamples(TimeSamples&& other) noexcept
|
||||
_small_values(std::move(other._small_values)),
|
||||
_values(std::move(other._values)),
|
||||
_offsets(std::move(other._offsets)),
|
||||
_value_array_storage(std::move(other._value_array_storage)),
|
||||
_value_array_refs(std::move(other._value_array_refs)),
|
||||
_type_id(other._type_id),
|
||||
_use_pod(other._use_pod),
|
||||
_use_value_array(other._use_value_array),
|
||||
_is_array(other._is_array),
|
||||
_array_size(other._array_size),
|
||||
_element_size(other._element_size),
|
||||
@@ -1613,6 +1616,7 @@ TimeSamples::TimeSamples(TimeSamples&& other) noexcept
|
||||
// Reset moved-from object to valid empty state
|
||||
other._type_id = 0;
|
||||
other._use_pod = false;
|
||||
other._use_value_array = false;
|
||||
other._is_array = false;
|
||||
other._array_size = 0;
|
||||
other._element_size = 0;
|
||||
@@ -1634,8 +1638,11 @@ TimeSamples& TimeSamples::operator=(TimeSamples&& other) noexcept {
|
||||
_offsets = std::move(other._offsets);
|
||||
_pod_samples = std::move(other._pod_samples);
|
||||
_small_values = std::move(other._small_values);
|
||||
_value_array_storage = std::move(other._value_array_storage);
|
||||
_value_array_refs = std::move(other._value_array_refs);
|
||||
_type_id = other._type_id;
|
||||
_use_pod = other._use_pod;
|
||||
_use_value_array = other._use_value_array;
|
||||
_is_array = other._is_array;
|
||||
_array_size = other._array_size;
|
||||
_element_size = other._element_size;
|
||||
@@ -1647,6 +1654,7 @@ TimeSamples& TimeSamples::operator=(TimeSamples&& other) noexcept {
|
||||
// Reset moved-from object to valid empty state
|
||||
other._type_id = 0;
|
||||
other._use_pod = false;
|
||||
other._use_value_array = false;
|
||||
other._is_array = false;
|
||||
other._array_size = 0;
|
||||
other._element_size = 0;
|
||||
@@ -1666,8 +1674,11 @@ TimeSamples::TimeSamples(const TimeSamples& other)
|
||||
_small_values(other._small_values),
|
||||
_values(other._values),
|
||||
_offsets(other._offsets),
|
||||
// _value_array_storage is copied in body to avoid TypeTraits issues
|
||||
_value_array_refs(other._value_array_refs),
|
||||
_type_id(other._type_id),
|
||||
_use_pod(other._use_pod),
|
||||
_use_value_array(other._use_value_array),
|
||||
_is_array(other._is_array),
|
||||
_array_size(other._array_size),
|
||||
_element_size(other._element_size),
|
||||
@@ -1676,6 +1687,11 @@ TimeSamples::TimeSamples(const TimeSamples& other)
|
||||
_dirty_start(other._dirty_start),
|
||||
_dirty_end(other._dirty_end),
|
||||
_pod_samples(other._pod_samples) {
|
||||
// Copy value array storage in body to avoid TypeTraits instantiation issues
|
||||
_value_array_storage.reserve(other._value_array_storage.size());
|
||||
for (const auto& v : other._value_array_storage) {
|
||||
_value_array_storage.push_back(v);
|
||||
}
|
||||
// Deep copy _array_values (vector of unique_ptr)
|
||||
_array_values.clear();
|
||||
_array_values.reserve(other._array_values.size());
|
||||
@@ -1700,6 +1716,7 @@ TimeSamples& TimeSamples::operator=(const TimeSamples& other) {
|
||||
_offsets = other._offsets;
|
||||
_type_id = other._type_id;
|
||||
_use_pod = other._use_pod;
|
||||
_use_value_array = other._use_value_array;
|
||||
_is_array = other._is_array;
|
||||
_array_size = other._array_size;
|
||||
_element_size = other._element_size;
|
||||
@@ -1709,6 +1726,13 @@ TimeSamples& TimeSamples::operator=(const TimeSamples& other) {
|
||||
_dirty_end = other._dirty_end;
|
||||
_pod_samples = other._pod_samples;
|
||||
_small_values = other._small_values;
|
||||
_value_array_refs = other._value_array_refs;
|
||||
// Copy value array storage element by element to avoid TypeTraits instantiation issues
|
||||
_value_array_storage.clear();
|
||||
_value_array_storage.reserve(other._value_array_storage.size());
|
||||
for (const auto& v : other._value_array_storage) {
|
||||
_value_array_storage.push_back(v);
|
||||
}
|
||||
|
||||
// Deep copy _array_values (vector of unique_ptr)
|
||||
_array_values.clear();
|
||||
|
||||
@@ -1391,6 +1391,7 @@ struct TimeSamples {
|
||||
_type_id = v.type_id();
|
||||
_use_value_array = true;
|
||||
_is_array = true;
|
||||
_use_pod = false; // Value array storage is not POD storage
|
||||
}
|
||||
|
||||
// Store in value array storage
|
||||
@@ -1989,7 +1990,8 @@ struct TimeSamples {
|
||||
}
|
||||
|
||||
// If _use_pod = false but unified storage has data, convert to generic samples
|
||||
if (!_times.empty() && _samples.empty()) {
|
||||
// Skip if using value array storage - that's handled below
|
||||
if (!_use_value_array && !_times.empty() && _samples.empty()) {
|
||||
if (_dirty) {
|
||||
update();
|
||||
}
|
||||
@@ -2113,6 +2115,39 @@ struct TimeSamples {
|
||||
return _samples;
|
||||
}
|
||||
|
||||
// Handle value array storage (from add_value_array_sample)
|
||||
if (_use_value_array && !_times.empty() && _samples.empty()) {
|
||||
if (_dirty) {
|
||||
update();
|
||||
}
|
||||
|
||||
_samples.clear();
|
||||
_samples.reserve(_times.size());
|
||||
|
||||
for (size_t i = 0; i < _times.size(); ++i) {
|
||||
Sample s;
|
||||
s.t = _times[i];
|
||||
|
||||
// Check dedup flag from _value_array_refs
|
||||
if (i < _value_array_refs.size()) {
|
||||
size_t storage_idx = get_value_array_index(_value_array_refs[i]);
|
||||
if (storage_idx < _value_array_storage.size()) {
|
||||
s.value = _value_array_storage[storage_idx];
|
||||
s.blocked = false;
|
||||
} else {
|
||||
s.value = value::Value(); // Invalid index
|
||||
s.blocked = true;
|
||||
}
|
||||
} else {
|
||||
s.value = value::Value();
|
||||
s.blocked = true;
|
||||
}
|
||||
|
||||
_samples.push_back(s);
|
||||
}
|
||||
return _samples;
|
||||
}
|
||||
|
||||
if (_dirty) {
|
||||
update();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user