writer: order dense name indexes by hash, then name
libhdf5 compares the name when two hashes are equal; the writer broke ties by insertion order, and libhdf5 could not find one of two names whose lookup3 hashes collide (k69209 / k155448). Test fails before the fix with h5py's KeyError. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -627,6 +627,45 @@ fn non_ascii_names_are_utf8() {
|
||||
assert_eq!(f.dataset("größe/wert").unwrap().read_i32().unwrap(), [1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names_whose_hashes_collide_are_found_by_name() {
|
||||
skip_if_no_python!();
|
||||
// "k69209" and "k155448" have the same lookup3 hash (0x3a0b13e6). The
|
||||
// dense name indexes (links: type 5, attributes: type 8) are ordered by
|
||||
// hash and then by name, and libhdf5's lookup relies on it. The writer
|
||||
// broke ties by insertion order, so with "k69209" added first libhdf5
|
||||
// could not open "k155448" by name.
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let mut b = FileBuilder::new();
|
||||
let mut g = b.create_group("g");
|
||||
for (i, n) in ["k69209", "k155448"]
|
||||
.into_iter()
|
||||
.chain((0..10).map(|_| ""))
|
||||
.enumerate()
|
||||
{
|
||||
let name = if n.is_empty() { format!("d{i}") } else { n.into() };
|
||||
g.create_dataset(&name).with_i32_data(&[i as i32]);
|
||||
}
|
||||
b.add_group(g.finish());
|
||||
let x = b.create_dataset("x");
|
||||
x.with_i32_data(&[0]);
|
||||
x.set_attr("k69209", AttrValue::I64(1));
|
||||
x.set_attr("k155448", AttrValue::I64(2));
|
||||
for i in 0..10 {
|
||||
x.set_attr(&format!("a{i}"), AttrValue::I64(10 + i));
|
||||
}
|
||||
let path = write(&dir, "collide.h5", b);
|
||||
let out = h5py(
|
||||
&path,
|
||||
"with h5py.File(path, 'r') as f:\n\
|
||||
\x20 g, a = f['g'], f['x'].attrs\n\
|
||||
\x20 print(json.dumps([int(g['k69209'][0]), int(g['k155448'][0]), 'k155448' in g,\n\
|
||||
\x20 int(a['k69209']), int(a['k155448']), 'k155448' in a]))",
|
||||
);
|
||||
assert_eq!(out, "[0, 1, true, 1, 2, true]");
|
||||
h5dump_ok(&path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_group_attribute_set_again_takes_the_new_value() {
|
||||
skip_if_no_python!();
|
||||
|
||||
Reference in New Issue
Block a user