Skip to content

Commit 0b89d23

Browse files
committed
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
1 parent ec18757 commit 0b89d23

File tree

7 files changed

+66
-28
lines changed

7 files changed

+66
-28
lines changed

servo/components/style/gecko/regen_atoms.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"""[1:] # NOQA: E501
2525

2626

27-
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*([^,]*),\s*([^)]*)\)',
27+
# Matches lines like `GK_ATOM(foo, "foo", 0x12345678, nsStaticAtom, PseudoElementAtom)`.
28+
PATTERN = re.compile('^GK_ATOM\(([^,]*),[^"]*"([^"]*)",\s*(0x[0-9a-f]+),\s*([^,]*),\s*([^)]*)\)',
2829
re.MULTILINE)
2930
FILE = "include/nsGkAtomList.h"
3031
CLASS = "nsGkAtoms"
@@ -52,10 +53,11 @@ def map_atom(ident):
5253

5354

5455
class Atom:
55-
def __init__(self, ident, value, ty, atom_type):
56+
def __init__(self, ident, value, hash, ty, atom_type):
5657
self.ident = "{}_{}".format(CLASS, ident)
5758
self.original_ident = ident
5859
self.value = value
60+
self.hash = hash
5961
# The Gecko type: "nsStaticAtom", "nsICSSPseudoElement", or "nsIAnonBoxPseudo"
6062
self.ty = ty
6163
# The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox",
@@ -104,7 +106,8 @@ def collect_atoms(objdir):
104106
with open(path) as f:
105107
content = f.read()
106108
for result in PATTERN.finditer(content):
107-
atoms.append(Atom(result.group(1), result.group(2), result.group(3), result.group(4)))
109+
atoms.append(Atom(result.group(1), result.group(2), result.group(3),
110+
result.group(4), result.group(5)))
108111
return atoms
109112

110113

xpcom/ds/Atom.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def __init__(self, ident, string, ty="nsStaticAtom"):
99
self.string = string
1010
self.ty = ty
1111
self.atom_type = self.__class__.__name__
12+
self.hash = hash_string(string)
1213

1314

1415
class PseudoElementAtom(Atom):
@@ -29,3 +30,25 @@ def __init__(self, ident, string):
2930
class InheritingAnonBoxAtom(AnonBoxAtom):
3031
def __init__(self, ident, string):
3132
AnonBoxAtom.__init__(self, ident, string)
33+
34+
35+
GOLDEN_RATIO_U32 = 0x9E3779B9
36+
37+
38+
def rotate_left_5(value):
39+
return ((value << 5) | (value >> 27)) & 0xFFFFFFFF
40+
41+
42+
def wrapping_multiply(x, y):
43+
return (x * y) & 0xFFFFFFFF
44+
45+
46+
# Calculate the precomputed hash of the static atom. This is a port of
47+
# mozilla::HashString(const char16_t*), which is what we use for atomizing
48+
# strings. An assertion in nsAtomTable::RegisterStaticAtoms ensures that
49+
# the value we compute here matches what HashString() would produce.
50+
def hash_string(s):
51+
h = 0
52+
for c in s:
53+
h = wrapping_multiply(GOLDEN_RATIO_U32, rotate_left_5(h) ^ ord(c))
54+
return h

xpcom/ds/StaticAtoms.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,9 +2351,9 @@ def verify():
23512351
def generate_nsgkatomlist_h(output, *ignore):
23522352
verify()
23532353
output.write("/* THIS FILE IS AUTOGENERATED BY StaticAtoms.py. DO NOT EDIT */\n\n"
2354-
"// GK_ATOM(identifier, string, gecko_type, atom_type)\n" +
2355-
"".join(["GK_ATOM(%s, \"%s\", %s, %s)\n" %
2356-
(a.ident, a.string, a.ty, a.atom_type)
2354+
"// GK_ATOM(identifier, string, hash, gecko_type, atom_type)\n" +
2355+
"".join(["GK_ATOM(%s, \"%s\", 0x%08x, %s, %s)\n" %
2356+
(a.ident, a.string, a.hash, a.ty, a.atom_type)
23572357
for a in STATIC_ATOMS]))
23582358

23592359

xpcom/ds/nsAtom.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#include "nsISupportsImpl.h"
1111
#include "nsString.h"
12-
#include "mozilla/HashFunctions.h"
1312
#include "mozilla/UniquePtr.h"
1413

1514
namespace mozilla {
@@ -104,10 +103,10 @@ class nsAtom
104103

105104
protected:
106105
// Used by nsStaticAtom.
107-
constexpr nsAtom(const char16_t* aStr, uint32_t aLength)
106+
constexpr nsAtom(const char16_t* aStr, uint32_t aLength, uint32_t aHash)
108107
: mLength(aLength)
109108
, mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static))
110-
, mHash(mozilla::HashString(aStr))
109+
, mHash(aHash)
111110
{}
112111

113112
// Used by nsDynamicAtom.
@@ -138,9 +137,14 @@ class nsStaticAtom : public nsAtom
138137
MozExternalRefCountType AddRef() = delete;
139138
MozExternalRefCountType Release() = delete;
140139

140+
// The static atom's precomputed hash value is an argument here, but it
141+
// must be the same as would be computed by mozilla::HashString(aStr),
142+
// which is what we use when atomizing strings. We compute this hash in
143+
// Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
144+
// hashes match.
141145
constexpr nsStaticAtom(const char16_t* aStr, uint32_t aLength,
142-
uint32_t aStringOffset)
143-
: nsAtom(aStr, aLength)
146+
uint32_t aHash, uint32_t aStringOffset)
147+
: nsAtom(aStr, aLength, aHash)
144148
, mStringOffset(aStringOffset)
145149
{}
146150

xpcom/ds/nsAtomTable.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,11 @@ nsAtomTable::RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
647647
MOZ_ASSERT(nsCRT::IsAscii(atom->String()));
648648
MOZ_ASSERT(NS_strlen(atom->String()) == atom->GetLength());
649649

650+
// This assertion ensures the static atom's precomputed hash value matches
651+
// what would be computed by mozilla::HashString(aStr), which is what we use
652+
// when atomizing strings. We compute this hash in Atom.py.
653+
MOZ_ASSERT(HashString(atom->String()) == atom->hash());
654+
650655
AtomTableKey key(atom);
651656
nsAtomSubTable& table = SelectSubTable(key);
652657
MutexAutoLock lock(table.mLock);

xpcom/ds/nsGkAtoms.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
1313
namespace mozilla {
1414
namespace detail {
1515

16-
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
1716
extern constexpr GkAtoms gGkAtoms = {
1817
// The initialization of each atom's string.
19-
#define GK_ATOM(name_, value_, type_, atom_type_) \
18+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
2019
u"" value_,
2120
#include "nsGkAtomList.h"
2221
#undef GK_ATOM
@@ -26,25 +25,25 @@ extern constexpr GkAtoms gGkAtoms = {
2625
// Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
2726
// to the number of chars (including the terminating '\0'). The |u""| prefix
2827
// converts |value_| to a 16-bit string.
29-
#define GK_ATOM(name_, value_, type_, atom_type_) \
28+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
3029
nsStaticAtom(u"" value_, \
3130
sizeof(value_) - 1, \
31+
hash_, \
3232
offsetof(GkAtoms, \
3333
mAtoms[static_cast<size_t>(GkAtoms::Atoms::name_)]) - \
3434
offsetof(GkAtoms, name_##_string)),
3535
#include "nsGkAtomList.h"
3636
#undef GK_ATOM
3737
}
3838
};
39-
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
4039

4140
} // namespace detail
4241
} // namespace mozilla
4342

4443
const nsStaticAtom* const nsGkAtoms::sAtoms = mozilla::detail::gGkAtoms.mAtoms;
4544

4645
// Definition of the pointer to the static atom.
47-
#define GK_ATOM(name_, value_, type_, atom_type_) \
46+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
4847
type_* nsGkAtoms::name_ = const_cast<type_*>(static_cast<const type_*>( \
4948
&mozilla::detail::gGkAtoms.mAtoms[ \
5049
static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::name_)]));

xpcom/ds/nsGkAtoms.h

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@
4848
// nsGkAtomList.h is generated by StaticAtoms.py and has entries that look
4949
// like this:
5050
//
51-
// GK_ATOM(one, "one", nsStaticAtom, Atom)
52-
// GK_ATOM(two, "two", nsICSSPseudoElement, PseudoElementAtom)
53-
// GK_ATOM(three, "three", nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
51+
// GK_ATOM(one, "one", 0x01234567, nsStaticAtom, Atom)
52+
// GK_ATOM(two, "two", 0x12345678, nsICSSPseudoElement, PseudoElementAtom)
53+
// GK_ATOM(three, "three", 0x23456789, nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
5454
//
5555
// After macro expansion, the atom definitions look like the following:
5656
//
@@ -120,14 +120,17 @@
120120
// // The initialization of the atoms themselves.
121121
// nsStaticAtom(
122122
// u"one", 3,
123+
// 0x01234567,
123124
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
124125
// offsetof(GkAtoms, one_string)),
125126
// nsStaticAtom(
126127
// u"two", 3,
128+
// 0x12345678,
127129
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
128130
// offsetof(GkAtoms, two_string)),
129131
// nsStaticAtom(
130132
// u"three", 3,
133+
// 0x23456789,
131134
// offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
132135
// offsetof(GkAtoms, three_string)),
133136
// }
@@ -156,12 +159,13 @@
156159

157160
// Trivial subclasses of nsStaticAtom so that function signatures can require
158161
// an atom from a specific atom list.
159-
#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
160-
class name_ : public nsStaticAtom \
161-
{ \
162-
public: \
163-
constexpr name_(const char16_t* aStr, uint32_t aLength, uint32_t aOffset) \
164-
: nsStaticAtom(aStr, aLength, aOffset) {} \
162+
#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
163+
class name_ : public nsStaticAtom \
164+
{ \
165+
public: \
166+
constexpr name_(const char16_t* aStr, uint32_t aLength, \
167+
uint32_t aHash, uint32_t aOffset) \
168+
: nsStaticAtom(aStr, aLength, aHash, aOffset) {} \
165169
};
166170

167171
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSAnonBoxPseudo)
@@ -181,14 +185,14 @@ namespace detail {
181185
struct GkAtoms
182186
{
183187
// The declaration of each atom's string.
184-
#define GK_ATOM(name_, value_, type_, atom_type_) \
188+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
185189
const char16_t name_##_string[sizeof(value_)];
186190
#include "nsGkAtomList.h"
187191
#undef GK_ATOM
188192

189193
// The enum value for each atom.
190194
enum class Atoms {
191-
#define GK_ATOM(name_, value_, type_, atom_type_) \
195+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
192196
name_,
193197
#include "nsGkAtomList.h"
194198
#undef GK_ATOM
@@ -221,7 +225,7 @@ class nsGkAtoms
221225
//
222226
// XXX: Eventually this should be combined with its definition and the
223227
// pointer should be made `constexpr`. See bug 1449787.
224-
#define GK_ATOM(name_, value_, type_, atom_type_) \
228+
#define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
225229
static type_* name_;
226230
#include "nsGkAtomList.h"
227231
#undef GK_ATOM

0 commit comments

Comments
 (0)