Bug 1483121 - Generate static atom hash in StaticAtoms.py. r=njn,emilio

Summary: Depends On D3286

Reviewers: njn!, emilio!

Tags: #secure-revision

Bug #: 1483121

Differential Revision: https://phabricator.services.mozilla.com/D3295
This commit is contained in:
Cameron McCormack 2018-08-15 15:52:42 +10:00
parent 426af33a36
commit be0a66bcfb
7 changed files with 66 additions and 28 deletions

View file

@ -24,7 +24,8 @@ PRELUDE = """
"""[1:] # NOQA: E501
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*([^,]*),\s*([^)]*)\)',
# Matches lines like `GK_ATOM(foo, "foo", 0x12345678, nsStaticAtom, PseudoElementAtom)`.
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*(0x[0-9a-f]+),\s*([^,]*),\s*([^)]*)\)',
re.MULTILINE)
FILE = "include/nsGkAtomList.h"
CLASS = "nsGkAtoms"
@ -52,10 +53,11 @@ def map_atom(ident):
class Atom:
def __init__(self, ident, value, ty, atom_type):
def __init__(self, ident, value, hash, ty, atom_type):
self.ident = "{}_{}".format(CLASS, ident)
self.original_ident = ident
self.value = value
self.hash = hash
# The Gecko type: "nsStaticAtom", "nsICSSPseudoElement", or "nsIAnonBoxPseudo"
self.ty = ty
# The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox",
@ -104,7 +106,8 @@ def collect_atoms(objdir):
with open(path) as f:
content = f.read()
for result in PATTERN.finditer(content):
atoms.append(Atom(result.group(1), result.group(2), result.group(3), result.group(4)))
atoms.append(Atom(result.group(1), result.group(2), result.group(3),
result.group(4), result.group(5)))
return atoms

View file

@ -9,6 +9,7 @@ class Atom():
self.string = string
self.ty = ty
self.atom_type = self.__class__.__name__
self.hash = hash_string(string)
class PseudoElementAtom(Atom):
@ -29,3 +30,25 @@ class NonInheritingAnonBoxAtom(AnonBoxAtom):
class InheritingAnonBoxAtom(AnonBoxAtom):
def __init__(self, ident, string):
AnonBoxAtom.__init__(self, ident, string)
GOLDEN_RATIO_U32 = 0x9E3779B9
def rotate_left_5(value):
return ((value << 5) | (value >> 27)) & 0xFFFFFFFF
def wrapping_multiply(x, y):
return (x * y) & 0xFFFFFFFF
# Calculate the precomputed hash of the static atom. This is a port of
# mozilla::HashString(const char16_t*), which is what we use for atomizing
# strings. An assertion in nsAtomTable::RegisterStaticAtoms ensures that
# the value we compute here matches what HashString() would produce.
def hash_string(s):
h = 0
for c in s:
h = wrapping_multiply(GOLDEN_RATIO_U32, rotate_left_5(h) ^ ord(c))
return h

View file

@ -2354,9 +2354,9 @@ def generate_nsgkatomlist_h(output, *ignore):
"#ifdef small\n"
"#undef small\n"
"#endif\n\n"
"// GK_ATOM(identifier, string, gecko_type, atom_type)\n" +
"".join(["GK_ATOM(%s, \"%s\", %s, %s)\n" %
(a.ident, a.string, a.ty, a.atom_type)
"// GK_ATOM(identifier, string, hash, gecko_type, atom_type)\n" +
"".join(["GK_ATOM(%s, \"%s\", 0x%08x, %s, %s)\n" %
(a.ident, a.string, a.hash, a.ty, a.atom_type)
for a in STATIC_ATOMS]))

View file

@ -9,7 +9,6 @@
#include "nsISupportsImpl.h"
#include "nsString.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
@ -104,10 +103,10 @@ public:
protected:
// Used by nsStaticAtom.
constexpr nsAtom(const char16_t* aStr, uint32_t aLength)
constexpr nsAtom(const char16_t* aStr, uint32_t aLength, uint32_t aHash)
: mLength(aLength)
, mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static))
, mHash(mozilla::HashString(aStr))
, mHash(aHash)
{}
// Used by nsDynamicAtom.
@ -138,9 +137,14 @@ public:
MozExternalRefCountType AddRef() = delete;
MozExternalRefCountType Release() = delete;
// The static atom's precomputed hash value is an argument here, but it
// must be the same as would be computed by mozilla::HashString(aStr),
// which is what we use when atomizing strings. We compute this hash in
// Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
// hashes match.
constexpr nsStaticAtom(const char16_t* aStr, uint32_t aLength,
uint32_t aStringOffset)
: nsAtom(aStr, aLength)
uint32_t aHash, uint32_t aStringOffset)
: nsAtom(aStr, aLength, aHash)
, mStringOffset(aStringOffset)
{}

View file

@ -647,6 +647,11 @@ nsAtomTable::RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
MOZ_ASSERT(nsCRT::IsAscii(atom->String()));
MOZ_ASSERT(NS_strlen(atom->String()) == atom->GetLength());
// This assertion ensures the static atom's precomputed hash value matches
// what would be computed by mozilla::HashString(aStr), which is what we use
// when atomizing strings. We compute this hash in Atom.py.
MOZ_ASSERT(HashString(atom->String()) == atom->hash());
AtomTableKey key(atom);
nsAtomSubTable& table = SelectSubTable(key);
MutexAutoLock lock(table.mLock);

View file

@ -13,10 +13,9 @@ NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
namespace mozilla {
namespace detail {
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
extern constexpr GkAtoms gGkAtoms = {
// The initialization of each atom's string.
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
u"" value_,
#include "nsGkAtomList.h"
#undef GK_ATOM
@ -26,9 +25,10 @@ extern constexpr GkAtoms gGkAtoms = {
// Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
// to the number of chars (including the terminating '\0'). The |u""| prefix
// converts |value_| to a 16-bit string.
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
nsStaticAtom(u"" value_, \
sizeof(value_) - 1, \
hash_, \
offsetof(GkAtoms, \
mAtoms[static_cast<size_t>(GkAtoms::Atoms::name_)]) - \
offsetof(GkAtoms, name_##_string)),
@ -36,7 +36,6 @@ extern constexpr GkAtoms gGkAtoms = {
#undef GK_ATOM
}
};
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
} // namespace detail
} // namespace mozilla
@ -44,7 +43,7 @@ MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
const nsStaticAtom* const nsGkAtoms::sAtoms = mozilla::detail::gGkAtoms.mAtoms;
// Definition of the pointer to the static atom.
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
type_* nsGkAtoms::name_ = const_cast<type_*>(static_cast<const type_*>( \
&mozilla::detail::gGkAtoms.mAtoms[ \
static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::name_)]));

View file

@ -48,9 +48,9 @@
// nsGkAtomList.h is generated by StaticAtoms.py and has entries that look
// like this:
//
// GK_ATOM(one, "one", nsStaticAtom, Atom)
// GK_ATOM(two, "two", nsICSSPseudoElement, PseudoElementAtom)
// GK_ATOM(three, "three", nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
// GK_ATOM(one, "one", 0x01234567, nsStaticAtom, Atom)
// GK_ATOM(two, "two", 0x12345678, nsICSSPseudoElement, PseudoElementAtom)
// GK_ATOM(three, "three", 0x23456789, nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
//
// After macro expansion, the atom definitions look like the following:
//
@ -120,14 +120,17 @@
// // The initialization of the atoms themselves.
// nsStaticAtom(
// u"one", 3,
// 0x01234567,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
// offsetof(GkAtoms, one_string)),
// nsStaticAtom(
// u"two", 3,
// 0x12345678,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
// offsetof(GkAtoms, two_string)),
// nsStaticAtom(
// u"three", 3,
// 0x23456789,
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
// offsetof(GkAtoms, three_string)),
// }
@ -156,12 +159,13 @@
// Trivial subclasses of nsStaticAtom so that function signatures can require
// an atom from a specific atom list.
#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
class name_ : public nsStaticAtom \
{ \
public: \
constexpr name_(const char16_t* aStr, uint32_t aLength, uint32_t aOffset) \
: nsStaticAtom(aStr, aLength, aOffset) {} \
#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
class name_ : public nsStaticAtom \
{ \
public: \
constexpr name_(const char16_t* aStr, uint32_t aLength, \
uint32_t aHash, uint32_t aOffset) \
: nsStaticAtom(aStr, aLength, aHash, aOffset) {} \
};
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSAnonBoxPseudo)
@ -181,14 +185,14 @@ namespace detail {
struct GkAtoms
{
// The declaration of each atom's string.
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
const char16_t name_##_string[sizeof(value_)];
#include "nsGkAtomList.h"
#undef GK_ATOM
// The enum value for each atom.
enum class Atoms {
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
name_,
#include "nsGkAtomList.h"
#undef GK_ATOM
@ -221,7 +225,7 @@ public:
//
// XXX: Eventually this should be combined with its definition and the
// pointer should be made `constexpr`. See bug 1449787.
#define GK_ATOM(name_, value_, type_, atom_type_) \
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
static type_* name_;
#include "nsGkAtomList.h"
#undef GK_ATOM