Gutschrift an @koraa.
Derzeit weist dieser Code eine Verwendung nach der kostenlosen Ausgabe auf:
void bugged(void)
{
XXH3_state_t *a = XXH3_createState();
XXH3_state_t *b = XXH3_createState();
XXH3_64bits_reset_withSeed(a, 0x1234567890abcdefull);
XXH3_copyState(b, a);
XXH3_freeState(a);
// Bug
XXH3_64bits_update(b, "BUGGED", strlen("BUGGED"));
XXH3_freeState(b);
}
Dies liegt daran, dass a->secret
auf a->customSecret
zeigt und XXH3_copyState
diesen Zeiger nicht aktualisiert (es ist buchstäblich nur memcpy
), also b->secret
zeigt auf a->customSecret
.
Nachdem a
freigegeben wurde, ist b->secret
jetzt ein ungültiger Zeiger.
Siehe Diskussion in #361.
Es gibt einige Optionen.
Die erste und einfachste Option, die keine Änderungen am Verhalten hat, ist diese:
XXH_PUBLIC_API XXH_errorcode
XXH3_copyState(XXH3_state_t* dst, const XXH3_state_t* src)
{
XXH_memcpy(dst, src, sizeof(XXH3_state_t));
if (src->secret == &src->customSecret[0]) {
dst->secret = &dst->customSecret[0];
}
return XXH_OK;
}
Dies ist jedoch ein wenig hackig.
Die zweite Möglichkeit besteht darin, eines der reservierten Felder zu verwenden, um festzustellen, um welche Art von Zustand es sich handelt, und dies zu verwenden, anstatt Rohzeiger zu vergleichen.
Während wir dies tun, könnten wir eine Fehlerprüfung hinzufügen, um eine Vermischung von 64-Bit- und 128-Bit-Zuständen zu verhindern. Dies würde das Verhalten ändern, aber diese Verwendung war sowieso nicht beabsichtigt und kann als UB angesehen werden.
Die dritte Option besteht darin, einen NULL
Zeiger für den Seed-Modus zu verwenden, und wenn er NULL ist, verwenden Sie customSecret
anstelle von secret
, aber dies würde eine Verzweigung hinzufügen. Es gibt jedoch bereits genug Overhead von der Zustandsverwaltung, dass es wahrscheinlich einen nicht wahrnehmbaren Unterschied machen würde.
Die letzte Option besteht darin, malloc()
eine Kopie des geheimen Zeigers zu erstellen.
Dadurch ändert sich die ABI, da sie nicht mehr vollständig im Stack-Speicher ausgeführt werden kann. Es wird auch für kSecret
hochgradig redundant sein.
Es ermöglicht jedoch, benutzerdefinierte Geheimnisse nach reset_withSeed()
ungültig zu machen und die Größe des Zustands zu verkleinern.
Ups, versehentlich den falschen Knopf gedrückt :facepalm:
Ich denke, es gibt eine vierte Option: Immer den Entropiepool in die Struktur kopieren; Dies würde jedoch dazu führen, dass der Pool die Größe des Standardgeheimnisses hat. Das mag zwar nett sein und die Grundlage für die Offline-Optimierung der Entropiepool-Generierung bilden.
uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data, size_t size);
Die Implementierung würde den XXH3-Zustand mit den gegebenen Daten "erweitern"; den Hash sofort zurückgeben, ohne den Zustand zu ändern ...
BEARBEITEN Dies würde die Beweglichkeit erhalten; welches IMO ein großer Segen für die Benutzerfreundlichkeit ist und für eine Rostintegration sehr geschätzt würde.
uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data, size_t size);
error: expected ')'
...XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t data,...
^
note: to match this '('
uint64_t XXH3_64bits_withEntropyPool(XXH3_state_t &pool, uint8_t...
^
1 error generated.
Was ist das? Ich weiß nicht, was du da vorhast... :smirk:
Beweglichkeit wäre ein nettes Feature und wäre mit einem Geheimnis mit fester Größe einfach.
Eigentlich wäre alles einfacher (und schneller) mit einem Secret mit fester Größe, aber wir wollen die API nicht durcheinander bringen.
Ich denke, die beste Option ist der NULL
Zeiger.
Es gibt bereits 5 Filialen am Anfang von XXH3_update
. Es schadet nicht, noch einen zu machen (zumal es nur benötigt wird, wenn der Puffer gefüllt ist)
Es ist auch zu beachten, dass x86_64 und i686 dies ohne Verzweigung tun können:
lea tmp, [state + offsetof (state::customSecret)]
test secret, secret
cmove secret, tmp
Dies ist auch branchenlos auf ARM
cmp secret, #0
it eq
addeq secret, state, offsetof(state::customSecret)
und auf AArch64:
add tmp, state, offsetof(state::customSecret)
cmp secret, #0
csel secret, tmp, secret, eq
Hilfreichster Kommentar
Ich denke, die beste Option ist der
NULL
Zeiger.Es gibt bereits 5 Filialen am Anfang von
XXH3_update
. Es schadet nicht, noch einen zu machen (zumal es nur benötigt wird, wenn der Puffer gefüllt ist)