maskit commented on code in PR #13621:
URL: https://github.com/apache/trafficserver/pull/13621#discussion_r4085903791


##########
src/proxy/http3/QPACK.cc:
##########
@@ -1147,20 +1149,30 @@ QPACK::_on_encoder_stream_read_ready(IOBufferReader 
&reader)
     reader.memcpy(&buf, 1);
     if (buf & 0x80) { // Insert With Name Reference
       bool        is_static;
-      uint16_t    index;
-      const char *name;
-      size_t      name_len;
-      const char *dummy;
-      size_t      dummy_len;
+      uint64_t    index;
+      const char *name      = nullptr;
+      size_t      name_len  = 0;
+      const char *dummy     = nullptr;
+      size_t      dummy_len = 0;
       char       *value;
       size_t      value_len;
       if (this->_read_insert_with_name_ref(reader, is_static, index, 
this->_arena, &value, value_len) < 0) {
         this->_abort_decode();
         return EVENT_DONE;
       }
-      QPACKDebug("Received Insert With Name Ref: is_static=%d, index=%d, 
value=%.*s", is_static, index, static_cast<int>(value_len),
-                 value);
-      StaticTable::lookup(index, &name, &name_len, &dummy, &dummy_len);
+      QPACKDebug("Received Insert With Name Ref: is_static=%d, index=%" PRIu64 
", value=%.*s", is_static, index,
+                 static_cast<int>(value_len), value);
+      XpackLookupResult result;
+      if (is_static) {
+        result = StaticTable::lookup(index, &name, &name_len, &dummy, 
&dummy_len);
+      } else {
+        result = this->_dynamic_table.lookup_relative(index, &name, &name_len, 
&dummy, &dummy_len);
+      }
+      if (result.match_type != XpackLookupResult::MatchType::EXACT) {
+        this->_arena.str_free(value);
+        this->_abort_decode();
+        return EVENT_DONE;
+      }
       this->_dynamic_table.insert_entry(name, name_len, value, value_len);

Review Comment:
   Confirmed. This came in with the dynamic branch; the `lookup_relative` 
change I suggested kept it. On master the name always came from the static 
table.
   
   RFC 9204 §3.2.2 explicitly allows it: "A new entry can reference an entry in 
the dynamic table that will be evicted when adding this new entry", and 
"implementations are cautioned to avoid deleting the referenced name or value" 
when that happens. Deterministic repro under ASan against a 128-byte table: 
insert a 62-byte name, then a 91-byte name (this evicts the first and wraps the 
storage), then insert using the name `lookup_relative(0)` returns:
   
   ```
   AddressSanitizer: memcpy-param-overlap ... in XpackDynamicTableStorage::write
   ```
   
   Copying the name first, the way `duplicate_entry()` does, fixes it. 47,112 
randomized aliasing inserts gave no corruption and no report. Here the copy can 
live in `_arena`, alongside `value`:
   
   ```cpp
   char *owned_name = this->_arena.str_store(name, name_len);
   this->_dynamic_table.insert_entry(owned_name, name_len, value, value_len);
   this->_arena.str_free(owned_name);
   ```
   
   For a regression test on the encoder stream: Set Dynamic Table Capacity 128, 
then those three inserts. A conforming encoder would also wait for the earlier 
inserts to be acknowledged before evicting them (§2.1.1), but the decoder 
doesn't depend on that, so the test doesn't need it. It also pins relative vs 
absolute, since an absolute `lookup(0)` would hit the evicted first entry.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to