// Minimal CWVUIDelegate embedder behavior that exposes the UAF.
// Drop into an iOS app that links ChromeWebView.framework (e.g. extend
// //ios/web_view/shell/shell_view_controller.m).
//
// Precondition modeled: a "recently closed tabs" / history feature that
// retains popupWebView.backForwardList past the popup's lifetime.

#import <ChromeWebView/ChromeWebView.h>

@interface POCViewController : UIViewController <CWVUIDelegate>
@property(nonatomic, strong) CWVWebView* mainWebView;
@property(nonatomic, strong) CWVWebView* popupWebView;
// Retained past popup lifetime — the dangerous reference.
@property(nonatomic, strong) CWVBackForwardList* lastClosedHistory;
@end

@implementation POCViewController

- (CWVWebView*)webView:(CWVWebView*)webView
    createWebViewWithConfiguration:(CWVWebViewConfiguration*)configuration
               forNavigationAction:(CWVNavigationAction*)action {
  self.popupWebView =
      [[CWVWebView alloc] initWithFrame:self.view.bounds
                          configuration:configuration];
  self.popupWebView.UIDelegate = self;
  [self.view addSubview:self.popupWebView];
  return self.popupWebView;
}

- (void)webViewDidClose:(CWVWebView*)webView {
  // Embedder grabs the back/forward list for a "recently closed" UI.
  // CWVBackForwardList is a public, strong-returnable Obj-C object
  // documented as the WKBackForwardList equivalent.
  self.lastClosedHistory = webView.backForwardList;

  // Standard WKUIDelegate-style behavior: release the popup.
  // -> -[CWVWebView dealloc] (NOT -shutDown)
  // -> ARC .cxx_destruct frees _webState, which frees NavigationManagerImpl.
  // self.lastClosedHistory.navigationManager is now dangling.
  [webView removeFromSuperview];
  if (webView == self.popupWebView) {
    self.popupWebView = nil;
  }

  // Later, the UI reads the retained list. Any of these dereference the
  // freed NavigationManagerImpl through a non-nil dangling pointer:
  dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"closed tab had %lu back entries, current=%@",
          (unsigned long)self.lastClosedHistory.backList.count,  // UAF
          self.lastClosedHistory.currentItem.URL);               // UAF
  });
}

@end
