Bug 61145 - [chromium] initialize SchemeRegistry from WebKit::initialize
Summary: [chromium] initialize SchemeRegistry from WebKit::initialize
Status: RESOLVED WONTFIX
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: jochen
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-19 14:35 PDT by jochen
Modified: 2013-03-07 20:58 PST (History)
5 users (show)

See Also:


Attachments
Patch (3.53 KB, patch)
2011-05-19 14:36 PDT, jochen
no flags Details | Formatted Diff | Diff
Patch (3.53 KB, patch)
2011-05-19 15:31 PDT, jochen
no flags Details | Formatted Diff | Diff
Patch (3.73 KB, patch)
2011-05-20 11:32 PDT, jochen
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description jochen 2011-05-19 14:35:56 PDT
[chromium] initialize SchemeRegistry from WebKit::initialize
Comment 1 jochen 2011-05-19 14:36:28 PDT
Created attachment 94118 [details]
Patch
Comment 2 jochen 2011-05-19 14:43:49 PDT
If we access WebSecurityOrigin from background threads, we might end up with initializing the SchemeRegistry while accessing it from another thread: See http://crbug.com/71786 for a tsan report

An alternative would be to invoke a WebSecurityOrigin right after calling WebKit::initialize (see http://codereview.chromium.org/7046013/)

wdyt
Comment 3 Michael Nordman 2011-05-19 14:51:10 PDT
Either way works, but i think having it baked into WebKit::initialize is nicer.
Comment 4 jochen 2011-05-19 15:31:01 PDT
Created attachment 94130 [details]
Patch
Comment 5 Darin Fisher (:fishd, Google) 2011-05-20 11:02:53 PDT
Comment on attachment 94130 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=94130&action=review

> Source/WebCore/platform/SchemeRegistry.h:42
> +    static void initialize();

maybe this should be named better?

initializeDefaultNoAccessSchemes
ensureDefaultNoAccessSchemesAreInitialized

why do we only need to worry about "no access" schemes?  what about the local ones?
Comment 6 jochen 2011-05-20 11:32:23 PDT
Created attachment 94248 [details]
Patch
Comment 7 jochen 2011-05-20 11:33:10 PDT
(In reply to comment #5)
> (From update of attachment 94130 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=94130&action=review
> 
> > Source/WebCore/platform/SchemeRegistry.h:42
> > +    static void initialize();
> 
> maybe this should be named better?
> 
> initializeDefaultNoAccessSchemes
> ensureDefaultNoAccessSchemesAreInitialized
> 
> why do we only need to worry about "no access" schemes?  what about the local ones?

I renamed it ensureDefaultSchemesAreInitialized and invoke all static methods that have local static maps
Comment 8 Darin Fisher (:fishd, Google) 2011-05-20 14:37:31 PDT
Comment on attachment 94248 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=94248&action=review

> Source/WebCore/platform/SchemeRegistry.h:39
> +    // Initialize the default list of schemes. Initialization is optional and

actually, i just realized a potential problem.  using these maps from a background
thread could be problematic if the foreground thread is mutating the maps, right?
there doesn't seem to be any protection for that.

can you say more about how we end up in a situation where we are accessing these
maps off of the main thread?
Comment 9 Michael Nordman 2011-05-20 16:49:52 PDT
(In reply to comment #8)
> (From update of attachment 94248 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=94248&action=review
> 
> > Source/WebCore/platform/SchemeRegistry.h:39
> > +    // Initialize the default list of schemes. Initialization is optional and
> 
> actually, i just realized a potential problem.  using these maps from a background
> thread could be problematic if the foreground thread is mutating the maps, right?
> there doesn't seem to be any protection for that.
> 
> can you say more about how we end up in a situation where we are accessing these
> maps off of the main thread?

WebCore::SecurityOrigin uses SchemeRegistry. There are other maps withing SecurityOrigin.cpp that are also not thread-safe.

DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ());
DEFINE_STATIC_LOCAL(URLSchemesMap, schemes, ());
Comment 10 Darin Fisher (:fishd, Google) 2011-05-20 17:14:19 PDT
maybe the answer is that these maps should only be mutable during app startup.  after that point, it becomes safe to mutate them on background threads.  if we are already accessing them on background threads and not observing a problem, then this is probably why.  maybe this should be made more clear though, and it should probably be enforced with assertions at least.
Comment 11 Darin Fisher (:fishd, Google) 2011-05-20 17:15:08 PDT
(In reply to comment #10)
> maybe the answer is that these maps should only be mutable during app startup.  after that point, it becomes safe to mutate them on background threads.  if we are already accessing them on background threads and not observing a problem, then this is probably why.  maybe this should be made more clear though, and it should probably be enforced with assertions at least.

oops, i meant: "after that point, it becomes safe to [read] them on background threads."
Comment 12 Michael Nordman 2011-05-20 18:08:22 PDT
(In reply to comment #11)
> (In reply to comment #10)
> > maybe the answer is that these maps should only be mutable during app startup.  after that point, it becomes safe to mutate them on background threads.  if we are already accessing them on background threads and not observing a problem, then this is probably why.  maybe this should be made more clear though, and it should probably be enforced with assertions at least.
> 
> oops, i meant: "after that point, it becomes safe to [read] them on background threads."

I'm not familiar with how or why the underlying maps mutate. It could be that we've been getting lucky. Just noticed another one of these static maps hidden away... no clue what it means for a domain to be forbidden from relaxation for a particular scheme. A particular use case that needs to be thoroughly thread-safe is producing and parsing originIdentifier strings so that we can covert to and from urls strings. I think if you ask SecurityOrigin to do one such conversion all of the static tables for that purpose uses will have been initted, but I don't know if any of those particular tables can mutate (like this forbidden relaxation thing).

Maybe the methods that rely on mutating unguarded static maps should assert main thread only?

static HashSet<String>& schemesForbiddenFromDomainRelaxation()
{
    DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ());
    return schemes;
}

void SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme)
bool SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(const String& scheme)
Comment 13 Sam Weinig 2011-05-21 16:43:17 PDT
(In reply to comment #11)
> (In reply to comment #10)
> > maybe the answer is that these maps should only be mutable during app startup.  after that point, it becomes safe to mutate them on background threads.  if we are already accessing them on background threads and not observing a problem, then this is probably why.  maybe this should be made more clear though, and it should probably be enforced with assertions at least.
> 
> oops, i meant: "after that point, it becomes safe to [read] them on background threads."

I think there is API (or maybe just SPI) exposed that allows mutation of these scheme maps at runtime, so I am not sure that would work.
Comment 14 jochen 2011-05-22 06:14:45 PDT
(In reply to comment #10)
> maybe the answer is that these maps should only be mutable during app startup.  after that point, it becomes safe to mutate them on background threads.  if we are already accessing them on background threads and not observing a problem, then this is probably why.  maybe this should be made more clear though, and it should probably be enforced with assertions at least.


oh, we _are_ observing problems. In our in-process copy of WebKit, we don't properly initialize these maps, so we end up getting races
Comment 15 jochen 2011-05-22 06:17:22 PDT
(In reply to comment #12)
> I'm not familiar with how or why the underlying maps mutate. It could be that we've been getting lucky. 

some of the maps are populated with default entries when they're first accessed. When we access security origins from different threads, we get a race: one thread reads the map, and it's auto-populated, while the other thread also tries to read the map
Comment 16 Michael Nordman 2011-05-22 12:29:47 PDT
> some of the maps are populated with default entries when they're first accessed. When we access security origins from different threads, we get a race: one thread reads the map, and it's auto-populated, while the other thread also tries to read the map

Maybe we should submit the following until we get this worked out better...
http://codereview.chromium.org/7054002/diff/2001/content/browser/in_process_webkit/webkit_thread.cc

There are a variety of "maps" ultimately utilized by this class, those that mutate w/o any guards around them are just not thread-safe. Only some of these "maps" are actually relevant to the functions we really need to access on the IO (and other threads) within chrome's main process. I think (but haven't confirmed this) that those needed do not mutate after initialized.

Maybe instead of using the WebSecurityOrigin instances (which exposes methods that are inherently not thread-safe) to perform those functions, we add new webkit API to perform exactly the originIdentifier cracking and producing functions we need... say a pair of static WebSecurityOrigin methods... WebKit::init ensures the maps used for those functions are initted.
Comment 17 Michael Nordman 2011-05-23 14:42:08 PDT
These methods look safe.

SecurityOrigin::toString()
SecurityOrigin::databaseIdentifier()

The SecurityOrigin constructor code paths are more questionable...

SchemeRegistry::shouldTreatURLSchemeAsNoAccess()
uses schemesWithUniqueOrigins() which can mutate, but apparently does not in the current code base since registerURLSchemeAsNoAccess() is only called from test_shel_webkit_init.

// in SecurityOrigin.cpp
schemeRequiresAuthority()  // Depends on initialization, but safe thereafter, map does not mutate

// from KURL.h
boo isDefaultPortForProtocol()  // Depends on initialization, but safe thereafter, map does not mutate
Comment 18 jochen 2011-08-02 10:59:12 PDT
closing his one, as I don't intend to continue to work on this for now
Comment 19 Eric Seidel (no email) 2011-09-06 15:32:15 PDT
Comment on attachment 94248 [details]
Patch

Cleared review? from attachment 94248 [details] so that this bug does not appear in http://webkit.org/pending-review.  If you would like this patch reviewed, please attach it to a new bug (or re-open this bug before marking it for review again).