Feature #10098 » tsafe_eql.patch
| string.c | ||
|---|---|---|
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* str.tsafe_eql?(other) -> true or false
|
||
|
*
|
||
|
* Compares each byte of +str+ against +other+, similarly to String#eql?, but
|
||
|
* performs the comparison in constant-time.
|
||
|
*
|
||
|
* This method is timing-safe if both strings are of equal length.
|
||
|
*/
|
||
|
static VALUE
|
||
|
rb_str_tsafe_eql(VALUE str1, VALUE str2)
|
||
|
{
|
||
|
long len, idx;
|
||
|
char result;
|
||
|
const char *buf1, *buf2;
|
||
|
str2 = StringValue(str2);
|
||
|
len = RSTRING_LEN(str1);
|
||
|
if (RSTRING_LEN(str2) != len) return Qfalse;
|
||
|
buf1 = RSTRING_PTR(str1);
|
||
|
buf2 = RSTRING_PTR(str2);
|
||
|
result = 0;
|
||
|
for (idx = 0; idx < len; idx++) {
|
||
|
result |= buf1[idx] ^ buf2[idx];
|
||
|
}
|
||
|
if (result == 0) return Qtrue;
|
||
|
return Qfalse;
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* string <=> other_string -> -1, 0, +1 or nil
|
||
|
*
|
||
| ... | ... | |
|
rb_define_method(rb_cString, "==", rb_str_equal, 1);
|
||
|
rb_define_method(rb_cString, "===", rb_str_equal, 1);
|
||
|
rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
|
||
|
rb_define_method(rb_cString, "tsafe_eql?", rb_str_tsafe_eql, 1);
|
||
|
rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
|
||
|
rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
|
||
|
rb_define_method(rb_cString, "+", rb_str_plus, 1);
|
||
| test/ruby/test_string.rb | ||
|---|---|---|
|
casetest(S("CaT"), S('cAt'), true) # find these in the case.
|
||
|
end
|
||
|
def test_TIMING_SAFE_EQUAL # 'tsafe_eql?'
|
||
|
assert_equal(true, S("foo").tsafe_eql?(S("foo")))
|
||
|
assert_equal(false, S("foo").tsafe_eql?(S("foO")))
|
||
|
assert_equal(true, S("f\x00oo").tsafe_eql?(S("f\x00oo")))
|
||
|
assert_equal(false, S("f\x00oo").tsafe_eql?(S("f\x00oO")))
|
||
|
end
|
||
|
def test_capitalize
|
||
|
assert_equal(S("Hello"), S("hello").capitalize)
|
||
|
assert_equal(S("Hello"), S("hELLO").capitalize)
|
||