Bug 176123 - Layering violation in Editor::createFragment
Summary: Layering violation in Editor::createFragment
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit Misc. (show other bugs)
Version: Safari 9
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Alexey Proskuryakov
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2017-08-30 13:56 PDT by Alexey Proskuryakov
Modified: 2017-09-29 19:11 PDT (History)
7 users (show)

See Also:


Attachments
proposed patch (26.02 KB, patch)
2017-08-30 14:11 PDT, Alexey Proskuryakov
no flags Details | Formatted Diff | Diff
proposed patch (25.71 KB, patch)
2017-08-30 16:32 PDT, Alexey Proskuryakov
no flags Details | Formatted Diff | Diff
proposed patch (25.71 KB, patch)
2017-08-31 09:22 PDT, Alexey Proskuryakov
darin: review+
Details | Formatted Diff | Diff
patch for landing (30.91 KB, patch)
2017-09-19 14:56 PDT, Alexey Proskuryakov
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Proskuryakov 2017-08-30 13:56:33 PDT
Pasting in a modern WebKit application calls WebCore::Editor::createFragment, which calls _WebCreateFragment from WebKitLegacy, which calls into AppKit, which calls into WebKitLegacy to create a DOMDocumentFragment and to generate temporary URLs. This is quite a layering violation, and a lot of legacy technology use.
Comment 1 Alexey Proskuryakov 2017-08-30 14:11:18 PDT
Created attachment 319396 [details]
proposed patch
Comment 2 Build Bot 2017-08-30 14:13:30 PDT
Attachment 319396 [details] did not pass style-queue:


ERROR: Source/WebKitLegacy/mac/WebView/WebFrame.mm:2295:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2579:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2589:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2600:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm:441:  Extra space before ( in function call  [whitespace/parens] [4]
Total errors found: 5 in 10 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 3 Alexey Proskuryakov 2017-08-30 16:32:52 PDT
Created attachment 319421 [details]
proposed patch

Build fix for accidental edit.
Comment 4 Build Bot 2017-08-30 16:35:14 PDT
Attachment 319421 [details] did not pass style-queue:


ERROR: Source/WebKitLegacy/mac/WebView/WebFrame.mm:2295:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2579:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2589:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2600:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
Total errors found: 4 in 10 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 5 Alex Christensen 2017-08-30 18:29:05 PDT
Comment on attachment 319421 [details]
proposed patch

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

> Source/WebCore/editing/cocoa/EditorCocoa.mm:57
> +#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)

This occurs many times in this patch.  Could we replace it with #if HAVE(SOMETHING)?
Comment 6 Sam Weinig 2017-08-30 20:44:47 PDT
Seems like the layering violation could be avoided by adding an EditorClient function.
Comment 7 Alexey Proskuryakov 2017-08-31 09:21:16 PDT
> This occurs many times in this patch.  Could we replace it with #if HAVE(SOMETHING)?

We could, but why? Checking versions in this manner is the norm in WebKit, and it makes it slightly easier to eventually remove the old code.

> Seems like the layering violation could be avoided by adding an EditorClient function.

I'm not sure what you mean by this. There is a whole chain of violations here, the worst being that AppKit calls into WebKitLegacy.
Comment 8 Alexey Proskuryakov 2017-08-31 09:22:57 PDT
Created attachment 319467 [details]
proposed patch

More build fixing.
Comment 9 Build Bot 2017-08-31 09:25:22 PDT
Attachment 319467 [details] did not pass style-queue:


ERROR: Source/WebKitLegacy/mac/WebView/WebFrame.mm:2295:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2579:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2589:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
ERROR: Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:2600:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
Total errors found: 4 in 10 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 10 Darin Adler 2017-09-03 20:31:57 PDT
Comment on attachment 319467 [details]
proposed patch

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

I don’t completely understand this patch, but I will say r=me I guess.

> Source/WebCore/editing/cocoa/EditorCocoa.mm:57
> +#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)

Instead of repeating this conditional three times, in its two different forms (old and new version), can we define something at the top of the file and use that three times? Or, better, define it in the header file so it can be used in WebKitLegacy too.

> Source/WebCore/editing/cocoa/EditorCocoa.mm:157
> +    // This function needs to be kept in sync with identically named one in WebKitLegacy, which is used on older OS versions.

Can we change WebKitLegacy to call this instead of keeping two copies around?

> Source/WebCore/editing/cocoa/EditorCocoa.mm:179
> +        @"WebResourceHandler": [WebArchiveResourceAsWebResourceHandler class],

TextKit code expects a WebResourceHandler to be an object, but you chose to implement it as a class instead. This will work, but seems an unusual choice.

> Source/WebCore/editing/cocoa/EditorCocoa.mm:191
> +    NSString *htmlFragmentString = [string _htmlDocumentFragmentString:NSMakeRange(0, [string length]) documentAttributes:attributesForAttributedStringConversion() subresources:&subresources];

I think the name here could be fragmentString, no need to prefix with "html".

> Source/WebCore/editing/cocoa/EditorCocoa.mm:192
> +    RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);

The result of DocumentFragment::create is a Ref, not a RefPtr. I suggest using auto here and letting this local variable be a Ref.

> Source/WebCore/editing/cocoa/EditorCocoa.mm:195
> +    result.fragment = fragment;

Should use WTFMove here to avoid a tiny bit of reference count churn.

> Source/WebCore/editing/cocoa/WebArchiveResourceAsWebResourceHandler.h:38
> +@interface WebArchiveResourceAsWebResourceHandler : NSObject {
> +@package
> +    RefPtr<WebCore::ArchiveResource> resource;
> +}
> +@end

As far as I can tell, this class itself is a WebResourceHandle. Then instances of the class are returned as WebResource objects. Both sort of treated as “informal protocols”. Do we really have to combine both together in one class like that? There is economy in doing it that way, but also subtlety that I find a bit confusing. The name of the class is also misleading, because the instances are not WebResourceHandler but that is what the class name implies. Normally the class name describes the role of the instances, not the role of the class object.

I think it would be good to emphasize the WebResourceHandler interface we intend to implement by defining it here in the interface, not just the implementation:

+ (id)resourceForData:(NSData *)data URL:(NSURL *)url MIMEType:(NSString *)mimeType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName;

I think it would be good to emphasize the WebResource interface we intend to implement by defining it here in the interface:

@property (nonatomic, readonly, copy) NSData *data;
@property (nonatomic, readonly, strong) NSURL *URL;
@property (nonatomic, readonly, copy) NSString *MIMEType;
@property (nonatomic, readonly, copy) NSString *textEncodingName;
@property (nonatomic, readonly, copy) NSString *frameName;

Except it seems that we only implement the URL property. Why is it OK for us to not implement the other properties?

> Source/WebCore/editing/cocoa/WebArchiveResourceAsWebResourceHandler.mm:45
> +    resource = WebCore::ArchiveResource::create(SharedBuffer::create([[data copy] autorelease]), URL, MIMEType, textEncodingName, frameName, nil);

Seems unnecessary to use autorelease here. Could use RetainPtr instead, by writing "adoptNS([data copy]).get()".

> Source/WebCore/editing/cocoa/WebArchiveResourceAsWebResourceHandler.mm:57
> +    if (!resource)
> +        return nil;

I don’t think this is needed, because the init function will self destruct if the resource is nil.

> Source/WebKitLegacy/mac/Misc/WebNSURLExtras.h:-77
> -#if TARGET_OS_IPHONE
> -// FIXME: This method name needs a prefix.
> -+ (NSURL *)uniqueURLWithRelativePart:(NSString *)relativePart;
> -#endif

You checked that there are no clients outside WebKit depending on this?

> Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm:440
> +// FIXME: Remove this function once we don't use it on any supported platform.

This comment has wording that is confusing. We already don’t use this function. It’s just here to make the "exp" file not cause a build failure. The comment should say something more like this:

// FIXME: Remove both this stub and the real version of this function below once we don't need the real version on any supported platform.
// This stub is not used outside WebKit, but it's here so we won't get a linker error.

> Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:1
> -/*
> + /*

Should undo this change.

> Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:7582
> -// This is used by AppKit and is included here so that WebDataProtocolScheme is only defined once.
> +#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300)
>  @implementation NSURL (WebDataURL)
>  
>  + (NSURL *)_web_uniqueWebDataURL

There is a call to this method in -[NSHTMLReader readDocumentFragment:]. Why is it OK to not compile it in newer versions of iOS and macOS?
Comment 11 Ryosuke Niwa 2017-09-15 13:25:37 PDT
Comment on attachment 319467 [details]
proposed patch

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

>> Source/WebKitLegacy/mac/Misc/WebNSURLExtras.h:-77
>> -#endif
> 
> You checked that there are no clients outside WebKit depending on this?

As far as I can tell, there's no use of this function outside WebKit at least in OS itself.

>> Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:7582
>>  + (NSURL *)_web_uniqueWebDataURL
> 
> There is a call to this method in -[NSHTMLReader readDocumentFragment:]. Why is it OK to not compile it in newer versions of iOS and macOS?

Indeed this appears to be still used.
Comment 12 Ryosuke Niwa 2017-09-15 13:29:42 PDT
Comment on attachment 319467 [details]
proposed patch

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

> Source/WebCore/platform/URL.h:78
> -    static URL fakeURLWithRelativePart(const String&);
> +    WEBCORE_EXPORT static URL fakeURLWithRelativePart(const String&);

We should either wrap this in if-def PLATFORM(COCOA) or rename it to something scary like deprecatedFakeURLWithRelativePart so that people don't start using it elsewhere.
Comment 13 Alexey Proskuryakov 2017-09-19 13:56:09 PDT
Comment on attachment 319467 [details]
proposed patch

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

>> Source/WebCore/editing/cocoa/WebArchiveResourceAsWebResourceHandler.h:38
>> +@end
> 
> As far as I can tell, this class itself is a WebResourceHandle. Then instances of the class are returned as WebResource objects. Both sort of treated as “informal protocols”. Do we really have to combine both together in one class like that? There is economy in doing it that way, but also subtlety that I find a bit confusing. The name of the class is also misleading, because the instances are not WebResourceHandler but that is what the class name implies. Normally the class name describes the role of the instances, not the role of the class object.
> 
> I think it would be good to emphasize the WebResourceHandler interface we intend to implement by defining it here in the interface, not just the implementation:
> 
> + (id)resourceForData:(NSData *)data URL:(NSURL *)url MIMEType:(NSString *)mimeType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName;
> 
> I think it would be good to emphasize the WebResource interface we intend to implement by defining it here in the interface:
> 
> @property (nonatomic, readonly, copy) NSData *data;
> @property (nonatomic, readonly, strong) NSURL *URL;
> @property (nonatomic, readonly, copy) NSString *MIMEType;
> @property (nonatomic, readonly, copy) NSString *textEncodingName;
> @property (nonatomic, readonly, copy) NSString *frameName;
> 
> Except it seems that we only implement the URL property. Why is it OK for us to not implement the other properties?

I'll split this into two classes. The archive class is not meant to mimic WebResource though - the only accessor called by TextKit is -URL, and it's arguably a bug that it relies on a method that's not documented to be required.

Naming is a challenge for me. Here is what I have for now:
- WebArchiveResourceWebResourceHandler - objects of this class are passed as values for the "WebResourceHandler" key.
- WebArchiveResourceFromNSAttributedString - the handler creates those, and they are returned from the NSAttributedString call.

>>> Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:7582
>>>  + (NSURL *)_web_uniqueWebDataURL
>> 
>> There is a call to this method in -[NSHTMLReader readDocumentFragment:]. Why is it OK to not compile it in newer versions of iOS and macOS?
> 
> Indeed this appears to be still used.

It is only used in implementation of an SPI call that is no longer used after this patch. But I agree, it is not right to remove it earlier than the SPI.
Comment 14 Alexey Proskuryakov 2017-09-19 14:56:19 PDT
Created attachment 321245 [details]
patch for landing

In the interest of getting this landed finally, I didn't implement some of the improvement suggestions (unifying compile time checks, de-duplicating the code, renaming fakeURLWithRelativePart).

Also fixed issues with attribute dictionary - one object was leaking, and another was getting over-released.
Comment 15 Build Bot 2017-09-19 14:59:21 PDT
Attachment 321245 [details] did not pass style-queue:


ERROR: Source/WebKitLegacy/mac/WebView/WebFrame.mm:2298:  Weird number of spaces at line-start.  Are you using a 4-space indent?  [whitespace/indent] [3]
Total errors found: 1 in 12 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 16 Alexey Proskuryakov 2017-09-19 18:20:44 PDT
Committed http://trac.webkit.org/r222239
Comment 17 Radar WebKit Bug Importer 2017-09-27 12:46:25 PDT
<rdar://problem/34693918>
Comment 18 mitz 2017-09-29 15:29:18 PDT
Comment on attachment 321245 [details]
patch for landing

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

> Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:7293
> +#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300)

-_web_uniqueWebDataURL is still being used in shipping macOS. This change caused Mail to crash when pasting rich text into a compose window.
Comment 19 Alexey Proskuryakov 2017-09-29 19:05:36 PDT
I'm not sure how I landed it with the #if, definitely intended to keep _web_uniqueWebDataURL intact.

The other cause for crashing is that I overlooked NSAttributedString SPI still being used in -[WebHTMLView(WebPrivate) _documentFragmentFromPasteboard:forType:inContext:subresources:].
Comment 20 Alexey Proskuryakov 2017-09-29 19:11:49 PDT
Reverted this unintended change in http://trac.webkit.org/r222676