Skip to content

Commit a67650f

Browse files
hashseedjasnell
authored andcommitted
deps: V8: cherry-pick 64-bit hash seed commits
This serves as mitigation for the so-called HashWick vulnerability. Original commit messages: commit 3833fef57368c53c6170559ffa524c8c69f16ee5 Author: Yang Guo <yangguo@chromium.org> Date: Thu Sep 20 11:43:13 2018 Refactor integer hashing function names We now clearly differentiate between: - unseeded hash for 32-bit integers - unseeded hash for 64-bit integers - seeded hash for 32-bit integers - seeded hash for strings R=bmeurer@chromium.org Bug: chromium:680662 Change-Id: I7459958c4158ee3501c962943dff8f33258bb5ce Reviewed-on: https://chromium-review.googlesource.com/1235973 Commit-Queue: Yang Guo <yangguo@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#56068} commit 95a979e02d7154e45b293261a6998c99d71fc238 Author: Yang Guo <yangguo@chromium.org> Date: Thu Sep 20 14:34:48 2018 Call into C++ to compute seeded integer hash R=bmeurer@chromium.org Bug: chromium:680662 Change-Id: I8dace89d576dfcc5833fd539ce698a9ade1cb5a0 Reviewed-on: https://chromium-review.googlesource.com/1235928 Commit-Queue: Yang Guo <yangguo@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#56091} commit 2c2af0022d5feb9e525a00a76cb15db9f3e38dba Author: Yang Guo <yangguo@chromium.org> Date: Thu Sep 27 16:37:57 2018 Use 64-bit for seeded integer hashes R=petermarshall@chromium.org Bug: chromium:680662 Change-Id: If48d1043dbe1e1bb695ec890c23e103a6cacf2d4 Reviewed-on: https://chromium-review.googlesource.com/1244220 Commit-Queue: Yang Guo <yangguo@chromium.org> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#56271} Refs: #23259 PR-URL: #23264 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent dc33b3e commit a67650f

19 files changed

+70
-108
lines changed

common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
'uv_library%': 'static_library',
2626

2727
'clang%': 0,
28-
28+
2929
'openssl_fips%': '',
3030

3131
# Default to -O0 for debug builds.

deps/v8/src/builtins/builtins-collections-gen.cc

+5-6
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
689689
Node* key_tagged, Variable* result,
690690
Label* entry_found,
691691
Label* not_found);
692-
Node* ComputeIntegerHashForString(Node* context, Node* string_key);
692+
Node* ComputeStringHash(Node* context, Node* string_key);
693693
void SameValueZeroString(Node* context, Node* key_string, Node* candidate_key,
694694
Label* if_same, Label* if_not_same);
695695

@@ -846,8 +846,7 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
846846
Node* table, Node* smi_key, Variable* result, Label* entry_found,
847847
Label* not_found) {
848848
Node* const key_untagged = SmiUntag(smi_key);
849-
Node* const hash =
850-
ChangeInt32ToIntPtr(ComputeIntegerHash(key_untagged, Int32Constant(0)));
849+
Node* const hash = ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
851850
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
852851
result->Bind(hash);
853852
FindOrderedHashTableEntry<CollectionType>(
@@ -862,7 +861,7 @@ template <typename CollectionType>
862861
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
863862
Node* context, Node* table, Node* key_tagged, Variable* result,
864863
Label* entry_found, Label* not_found) {
865-
Node* const hash = ComputeIntegerHashForString(context, key_tagged);
864+
Node* const hash = ComputeStringHash(context, key_tagged);
866865
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
867866
result->Bind(hash);
868867
FindOrderedHashTableEntry<CollectionType>(
@@ -920,8 +919,8 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
920919
result, entry_found, not_found);
921920
}
922921

923-
Node* CollectionsBuiltinsAssembler::ComputeIntegerHashForString(
924-
Node* context, Node* string_key) {
922+
Node* CollectionsBuiltinsAssembler::ComputeStringHash(Node* context,
923+
Node* string_key) {
925924
VARIABLE(var_result, MachineType::PointerRepresentation());
926925

927926
Label hash_not_computed(this), done(this, &var_result);

deps/v8/src/code-stub-assembler.cc

+18-51
Original file line numberDiff line numberDiff line change
@@ -253,40 +253,6 @@ HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR);
253253
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST);
254254
#undef HEAP_CONSTANT_TEST
255255

256-
TNode<Int64T> CodeStubAssembler::HashSeed() {
257-
DCHECK(Is64());
258-
TNode<HeapObject> hash_seed_root =
259-
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
260-
return TNode<Int64T>::UncheckedCast(LoadObjectField(
261-
hash_seed_root, ByteArray::kHeaderSize, MachineType::Int64()));
262-
}
263-
264-
TNode<Int32T> CodeStubAssembler::HashSeedHigh() {
265-
DCHECK(!Is64());
266-
#ifdef V8_TARGET_BIG_ENDIAN
267-
static int kOffset = 0;
268-
#else
269-
static int kOffset = kInt32Size;
270-
#endif
271-
TNode<HeapObject> hash_seed_root =
272-
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
273-
return TNode<Int32T>::UncheckedCast(LoadObjectField(
274-
hash_seed_root, ByteArray::kHeaderSize + kOffset, MachineType::Int32()));
275-
}
276-
277-
TNode<Int32T> CodeStubAssembler::HashSeedLow() {
278-
DCHECK(!Is64());
279-
#ifdef V8_TARGET_BIG_ENDIAN
280-
static int kOffset = kInt32Size;
281-
#else
282-
static int kOffset = 0;
283-
#endif
284-
TNode<HeapObject> hash_seed_root =
285-
TNode<HeapObject>::UncheckedCast(LoadRoot(Heap::kHashSeedRootIndex));
286-
return TNode<Int32T>::UncheckedCast(LoadObjectField(
287-
hash_seed_root, ByteArray::kHeaderSize + kOffset, MachineType::Int32()));
288-
}
289-
290256
Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
291257
if (mode == SMI_PARAMETERS) {
292258
return SmiConstant(value);
@@ -7709,14 +7675,9 @@ template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
77097675
TNode<GlobalDictionary>, TNode<Name>, Label*, TVariable<IntPtrT>*, Label*,
77107676
int, LookupMode);
77117677

7712-
Node* CodeStubAssembler::ComputeIntegerHash(Node* key) {
7713-
return ComputeIntegerHash(key, IntPtrConstant(kZeroHashSeed));
7714-
}
7715-
7716-
Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
7717-
// See v8::internal::ComputeIntegerHash()
7678+
Node* CodeStubAssembler::ComputeUnseededHash(Node* key) {
7679+
// See v8::internal::ComputeUnseededHash()
77187680
Node* hash = TruncateIntPtrToInt32(key);
7719-
hash = Word32Xor(hash, seed);
77207681
hash = Int32Add(Word32Xor(hash, Int32Constant(0xFFFFFFFF)),
77217682
Word32Shl(hash, Int32Constant(15)));
77227683
hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
@@ -7727,6 +7688,21 @@ Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
77277688
return Word32And(hash, Int32Constant(0x3FFFFFFF));
77287689
}
77297690

7691+
Node* CodeStubAssembler::ComputeSeededHash(Node* key) {
7692+
Node* const function_addr =
7693+
ExternalConstant(ExternalReference::compute_integer_hash());
7694+
Node* const isolate_ptr =
7695+
ExternalConstant(ExternalReference::isolate_address(isolate()));
7696+
7697+
MachineType type_ptr = MachineType::Pointer();
7698+
MachineType type_uint32 = MachineType::Uint32();
7699+
7700+
Node* const result =
7701+
CallCFunction2(type_uint32, type_ptr, type_uint32, function_addr,
7702+
isolate_ptr, TruncateIntPtrToInt32(key));
7703+
return result;
7704+
}
7705+
77307706
void CodeStubAssembler::NumberDictionaryLookup(
77317707
TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
77327708
Label* if_found, TVariable<IntPtrT>* var_entry, Label* if_not_found) {
@@ -7737,16 +7713,7 @@ void CodeStubAssembler::NumberDictionaryLookup(
77377713
TNode<IntPtrT> capacity = SmiUntag(GetCapacity<NumberDictionary>(dictionary));
77387714
TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));
77397715

7740-
TNode<Int32T> int32_seed;
7741-
7742-
if (Is64()) {
7743-
int32_seed = TruncateInt64ToInt32(HashSeed());
7744-
} else {
7745-
int32_seed = HashSeedLow();
7746-
}
7747-
7748-
TNode<WordT> hash =
7749-
ChangeUint32ToWord(ComputeIntegerHash(intptr_index, int32_seed));
7716+
TNode<WordT> hash = ChangeUint32ToWord(ComputeSeededHash(intptr_index));
77507717
Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);
77517718

77527719
// See Dictionary::FirstProbe().

deps/v8/src/code-stub-assembler.h

+2-6
Original file line numberDiff line numberDiff line change
@@ -450,10 +450,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
450450
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST)
451451
#undef HEAP_CONSTANT_TEST
452452

453-
TNode<Int64T> HashSeed();
454-
TNode<Int32T> HashSeedHigh();
455-
TNode<Int32T> HashSeedLow();
456-
457453
Node* IntPtrOrSmiConstant(int value, ParameterMode mode);
458454
TNode<Smi> LanguageModeConstant(LanguageMode mode) {
459455
return SmiConstant(static_cast<int>(mode));
@@ -2288,8 +2284,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
22882284
int inlined_probes = kInlinedDictionaryProbes,
22892285
LookupMode mode = kFindExisting);
22902286

2291-
Node* ComputeIntegerHash(Node* key);
2292-
Node* ComputeIntegerHash(Node* key, Node* seed);
2287+
Node* ComputeUnseededHash(Node* key);
2288+
Node* ComputeSeededHash(Node* key);
22932289

22942290
void NumberDictionaryLookup(TNode<NumberDictionary> dictionary,
22952291
TNode<IntPtrT> intptr_index, Label* if_found,

deps/v8/src/compiler/effect-control-linearizer.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -4768,8 +4768,8 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) {
47684768
}
47694769
}
47704770

4771-
Node* EffectControlLinearizer::ComputeIntegerHash(Node* value) {
4772-
// See v8::internal::ComputeIntegerHash()
4771+
Node* EffectControlLinearizer::ComputeUnseededHash(Node* value) {
4772+
// See v8::internal::ComputeUnseededHash()
47734773
value = __ Int32Add(__ Word32Xor(value, __ Int32Constant(0xFFFFFFFF)),
47744774
__ Word32Shl(value, __ Int32Constant(15)));
47754775
value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(12)));
@@ -4787,7 +4787,7 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key(
47874787
Node* key = NodeProperties::GetValueInput(node, 1);
47884788

47894789
// Compute the integer hash code.
4790-
Node* hash = ChangeUint32ToUintPtr(ComputeIntegerHash(key));
4790+
Node* hash = ChangeUint32ToUintPtr(ComputeUnseededHash(key));
47914791

47924792
Node* number_of_buckets = ChangeSmiToIntPtr(__ LoadField(
47934793
AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets(), table));

deps/v8/src/compiler/effect-control-linearizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
182182
Node* BuildFloat64RoundDown(Node* value);
183183
Node* BuildFloat64RoundTruncate(Node* input);
184184
Node* BuildUint32Mod(Node* lhs, Node* rhs);
185-
Node* ComputeIntegerHash(Node* value);
185+
Node* ComputeUnseededHash(Node* value);
186186
Node* LowerStringComparison(Callable const& callable, Node* node);
187187
Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind);
188188

deps/v8/src/external-reference.cc

+9
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,15 @@ ExternalReference ExternalReference::jsreceiver_create_identity_hash(
764764
return ExternalReference(Redirect(FUNCTION_ADDR(f)));
765765
}
766766

767+
static uint32_t ComputeSeededIntegerHash(Isolate* isolate, uint32_t key) {
768+
DisallowHeapAllocation no_gc;
769+
return ComputeSeededHash(key, isolate->heap()->HashSeed());
770+
}
771+
772+
ExternalReference ExternalReference::compute_integer_hash() {
773+
return ExternalReference(Redirect(FUNCTION_ADDR(ComputeSeededIntegerHash)));
774+
}
775+
767776
ExternalReference
768777
ExternalReference::copy_fast_number_jsarray_elements_to_typed_array() {
769778
return ExternalReference(

deps/v8/src/external-reference.h

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class StatsCounter;
8383
V(address_of_uint32_bias, "uint32_bias") \
8484
V(bytecode_size_table_address, "Bytecodes::bytecode_size_table_address") \
8585
V(check_object_type, "check_object_type") \
86+
V(compute_integer_hash, "ComputeSeededHash") \
8687
V(compute_output_frames_function, "Deoptimizer::ComputeOutputFrames()") \
8788
V(copy_fast_number_jsarray_elements_to_typed_array, \
8889
"copy_fast_number_jsarray_elements_to_typed_array") \

deps/v8/src/frames.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2133,7 +2133,7 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
21332133
InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
21342134
isolate_->counters()->pc_to_code()->Increment();
21352135
DCHECK(base::bits::IsPowerOfTwo(kInnerPointerToCodeCacheSize));
2136-
uint32_t hash = ComputeIntegerHash(
2136+
uint32_t hash = ComputeUnseededHash(
21372137
ObjectAddressForHashing(reinterpret_cast<void*>(inner_pointer)));
21382138
uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
21392139
InnerPointerToCodeCacheEntry* entry = cache(index);

deps/v8/src/objects-inl.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -2980,14 +2980,14 @@ bool NumberDictionaryBaseShape::IsMatch(uint32_t key, Object* other) {
29802980
}
29812981

29822982
uint32_t NumberDictionaryBaseShape::Hash(Isolate* isolate, uint32_t key) {
2983-
return ComputeIntegerHash(key, isolate->heap()->HashSeed());
2983+
return ComputeSeededHash(key, isolate->heap()->HashSeed());
29842984
}
29852985

29862986
uint32_t NumberDictionaryBaseShape::HashForObject(Isolate* isolate,
29872987
Object* other) {
29882988
DCHECK(other->IsNumber());
2989-
return ComputeIntegerHash(static_cast<uint32_t>(other->Number()),
2990-
isolate->heap()->HashSeed());
2989+
return ComputeSeededHash(static_cast<uint32_t>(other->Number()),
2990+
isolate->heap()->HashSeed());
29912991
}
29922992

29932993
Handle<Object> NumberDictionaryBaseShape::AsHandle(Isolate* isolate,
@@ -3067,18 +3067,18 @@ uint32_t ObjectHashTableShape::HashForObject(Isolate* isolate, Object* other) {
30673067
Object* Object::GetSimpleHash(Object* object) {
30683068
DisallowHeapAllocation no_gc;
30693069
if (object->IsSmi()) {
3070-
uint32_t hash = ComputeIntegerHash(Smi::ToInt(object));
3070+
uint32_t hash = ComputeUnseededHash(Smi::ToInt(object));
30713071
return Smi::FromInt(hash & Smi::kMaxValue);
30723072
}
30733073
if (object->IsHeapNumber()) {
30743074
double num = HeapNumber::cast(object)->value();
30753075
if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
3076-
// Use ComputeIntegerHash for all values in Signed32 range, including -0,
3076+
// Use ComputeUnseededHash for all values in Signed32 range, including -0,
30773077
// which is considered equal to 0 because collections use SameValueZero.
30783078
uint32_t hash;
30793079
// Check range before conversion to avoid undefined behavior.
30803080
if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
3081-
hash = ComputeIntegerHash(FastD2I(num));
3081+
hash = ComputeUnseededHash(FastD2I(num));
30823082
} else {
30833083
hash = ComputeLongHash(double_to_uint64(num));
30843084
}

deps/v8/src/objects/bigint.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class V8_EXPORT_PRIVATE BigInt : public BigIntBase {
137137
bool ToBoolean() { return !is_zero(); }
138138
uint32_t Hash() {
139139
// TODO(jkummerow): Improve this. At least use length and sign.
140-
return is_zero() ? 0 : ComputeIntegerHash(static_cast<uint32_t>(digit(0)));
140+
return is_zero() ? 0 : ComputeLongHash(static_cast<uint64_t>(digit(0)));
141141
}
142142

143143
static bool EqualToString(Isolate* isolate, Handle<BigInt> x,

deps/v8/src/objects/ordered-hash-table.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class OrderedHashTable : public OrderedHashTableBase {
144144
// This special cases for Smi, so that we avoid the HandleScope
145145
// creation below.
146146
if (key->IsSmi()) {
147-
uint32_t hash = ComputeIntegerHash(Smi::ToInt(key));
147+
uint32_t hash = ComputeUnseededHash(Smi::ToInt(key));
148148
return HashToEntry(hash & Smi::kMaxValue);
149149
}
150150
HandleScope scope(isolate);

deps/v8/src/profiler/allocation-tracker.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ void AllocationTracker::AllocationEvent(Address addr, int size) {
239239

240240

241241
static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
242-
return ComputeIntegerHash(static_cast<uint32_t>(id));
242+
return ComputeUnseededHash(static_cast<uint32_t>(id));
243243
}
244244

245245

deps/v8/src/profiler/heap-snapshot-generator.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
535535
heap_->HashSeed());
536536
intptr_t element_count = info->GetElementCount();
537537
if (element_count != -1) {
538-
id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count));
538+
id ^= ComputeUnseededHash(static_cast<uint32_t>(element_count));
539539
}
540540
return id << 1;
541541
}

deps/v8/src/profiler/heap-snapshot-generator.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class HeapEntriesMap {
309309

310310
private:
311311
static uint32_t Hash(HeapThing thing) {
312-
return ComputeIntegerHash(
312+
return ComputeUnseededHash(
313313
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
314314
}
315315

@@ -520,7 +520,7 @@ class NativeObjectsExplorer {
520520

521521
struct RetainedInfoHasher {
522522
std::size_t operator()(v8::RetainedObjectInfo* info) const {
523-
return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
523+
return ComputeUnseededHash(static_cast<uint32_t>(info->GetHash()));
524524
}
525525
};
526526
struct RetainedInfoEquals {

deps/v8/src/profiler/profile-generator.cc

+6-6
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,16 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
8484
}
8585

8686
uint32_t CodeEntry::GetHash() const {
87-
uint32_t hash = ComputeIntegerHash(tag());
87+
uint32_t hash = ComputeUnseededHash(tag());
8888
if (script_id_ != v8::UnboundScript::kNoScriptId) {
89-
hash ^= ComputeIntegerHash(static_cast<uint32_t>(script_id_));
90-
hash ^= ComputeIntegerHash(static_cast<uint32_t>(position_));
89+
hash ^= ComputeUnseededHash(static_cast<uint32_t>(script_id_));
90+
hash ^= ComputeUnseededHash(static_cast<uint32_t>(position_));
9191
} else {
92-
hash ^= ComputeIntegerHash(
92+
hash ^= ComputeUnseededHash(
9393
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
94-
hash ^= ComputeIntegerHash(
94+
hash ^= ComputeUnseededHash(
9595
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
96-
hash ^= ComputeIntegerHash(line_number_);
96+
hash ^= ComputeUnseededHash(line_number_);
9797
}
9898
return hash;
9999
}

deps/v8/src/profiler/profile-generator.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ class ProfileNode {
243243
};
244244
struct Hasher {
245245
std::size_t operator()(CodeEntryAndLineNumber pair) const {
246-
return pair.code_entry->GetHash() ^ ComputeIntegerHash(pair.line_number);
246+
return pair.code_entry->GetHash() ^ ComputeUnseededHash(pair.line_number);
247247
}
248248
};
249249

0 commit comments

Comments
 (0)