New issue
Advanced search Search tips

Issue 617305 link

Starred by 1 user

Issue metadata

Status: Fixed
Owner:
Closed: Jun 2016
Cc:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 2
Type: Bug

Blocking:
issue 607996



Sign in to add a comment

FocusManagerTest.AdvanceFocusStaysInWidget crash under UBSan vptr

Project Member Reported by krasin@chromium.org, Jun 3 2016

Issue description

Version: tip
OS: Linux x86-64

Per 'UBSanVptr Linux' bot we have a problem with FocusManagerTest.AdvanceFocusStaysInWidget:

Received signal 11 SEGV_MAPERR 000000000000
#0 0x000001b529b6 base::debug::(anonymous namespace)::StackDumpSignalHandler()
#1 0x7f3af41e3330 <unknown>
#2 0x000001411d16 views::FocusManager::ViewRemoved()
#3 0x000001463ed7 views::Widget::OnNativeWidgetDestroying()
#4 0x0000014b796c views::NativeWidgetAura::OnWindowDestroying()
#5 0x00000125c393 aura::Window::~Window()
#6 0x00000125e280 aura::Window::~Window()
#7 0x0000014b9fb8 views::NativeWidgetAura::~NativeWidgetAura()
#8 0x0000014ba510 views::NativeWidgetAura::~NativeWidgetAura()
#9 0x000001457495 views::Widget::~Widget()
#10 0x00000079e126 views::FocusManagerTest_AdvanceFocusStaysInWidget_Test::TestBody()
#11 0x000001be6e07 testing::Test::Run()
#12 0x000001be81de testing::TestInfo::Run()
#13 0x000001be9122 testing::TestCase::Run()
#14 0x000001bf6228 testing::internal::UnitTestImpl::RunAllTests()
#15 0x000001bf55f9 testing::internal::HandleExceptionsInMethodIfSupported<>()
#16 0x000001bf53ed testing::UnitTest::Run()
#17 0x000000a0b4c0 base::TestSuite::Run()
#18 0x000000a1c164 base::(anonymous namespace)::LaunchUnitTestsInternal()
#19 0x000000a1c019 base::LaunchUnitTests()
#20 0x0000008a9c40 views::ViewsTestSuite::RunTests()
#21 0x0000007efadb main
#22 0x7f3af3c19f45 __libc_start_main
#23 0x000000485f31 <unknown>
  r8: 0000000001463d80  r9: 00007f3af46d8b40 r10: 00000000025747d0 r11: 00007f3af3d7f790
 r12: 9ddfea08eb382d69 r13: 00000000032924b0 r14: 0000000000000000 r15: 00000243902b0310
  di: 00000243902b0310  si: 0000000000000000  bp: 00007ffd88f04640  bx: ddd1ce1e7c5e8d3e
  dx: f1db9905bf83315d  ax: 000000000000005d  cx: 562878a759d8ad85  sp: 00007ffd88f04610
  ip: 0000000001411d16 efl: 0000000000010206 cgf: 0000000000000033 erf: 0000000000000004
 trp: 000000000000000e msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]

So far it seems like a null pointer access. Trying to reproduce it locally with is_ubsan_null=true
 
Reproduced:

$ gn gen //out/gn-vptr-null '--args=is_ubsan_vptr=true is_ubsan_no_recover=true is_ubsan_null=true is_debug=false is_component_build=false symbol_level=1 dcheck_always_on=true' --check
$ ninja -C out/gn-vptr-null views_unittests
$ ./out/gn-vptr-null/views_unittests --gtest_filter=FocusManagerTest.AdvanceFocusStaysInWidget
...
[ RUN      ] FocusManagerTest.AdvanceFocusStaysInWidget
../../ui/views/focus/focus_manager.cc:520:33: runtime error: member call on null pointer of type 'views::View'
    #0 0x165a7ed in views::FocusManager::ViewRemoved(views::View*) out/gn-vptr-null/../../ui/views/focus/focus_manager.cc:520:33
    #1 0x16ba2de in views::Widget::OnNativeWidgetDestroying() out/gn-vptr-null/../../ui/views/widget/widget.cc:1072:24
    #2 0x1715a69 in views::NativeWidgetAura::OnWindowDestroying(aura::Window*) out/gn-vptr-null/../../ui/views/widget/native_widget_aura.cc:846:14
    #3 0x14747bd in aura::Window::~Window() out/gn-vptr-null/../../ui/aura/window.cc:111:16
    #4 0x1476964 in aura::Window::~Window() out/gn-vptr-null/../../ui/aura/window.cc:104:19
    #5 0x1718f90 in views::NativeWidgetAura::~NativeWidgetAura() out/gn-vptr-null/../../ui/views/widget/native_widget_aura.cc:990:5
    #6 0x17194f4 in views::NativeWidgetAura::~NativeWidgetAura() out/gn-vptr-null/../../ui/views/widget/native_widget_aura.cc:985:39
    #7 0x16ac6af in views::Widget::~Widget() out/gn-vptr-null/../../ui/views/widget/widget.cc:174:5
    #8 0x7c538c in views::FocusManagerTest_AdvanceFocusStaysInWidget_Test::TestBody() out/gn-vptr-null/../../ui/views/focus/focus_manager_unittest.cc:915:1
    #9 0x1fdbe07 in testing::Test::Run() out/gn-vptr-null/../../testing/gtest/src/gtest.cc:2474:5
    #10 0x1fdd45e in testing::TestInfo::Run() out/gn-vptr-null/../../testing/gtest/src/gtest.cc:2656:11
    #11 0x1fde5b7 in testing::TestCase::Run() out/gn-vptr-null/../../testing/gtest/src/gtest.cc:2774:28
    #12 0x1feb957 in testing::internal::UnitTestImpl::RunAllTests() out/gn-vptr-null/../../testing/gtest/src/gtest.cc:4647:43
    #13 0x1fead74 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*
) out/gn-vptr-null/../../testing/gtest/src/gtest.cc:2458:12
    #14 0x1feab0c in testing::UnitTest::Run() out/gn-vptr-null/../../testing/gtest/src/gtest.cc:4255:10
    #15 0xa456fa in RUN_ALL_TESTS out/gn-vptr-null/../../testing/gtest/include/gtest/gtest.h:2237:46
    #16 0xa456fa in base::TestSuite::Run() out/gn-vptr-null/../../base/test/test_suite.cc:230
    #17 0xa58ac3 in Run out/gn-vptr-null/../../base/callback.h:397:12
    #18 0xa58ac3 in base::(anonymous namespace)::LaunchUnitTestsInternal(base::Callback<int (), (base::internal::CopyMode)1> const&, int, int, bool, base::Callback<void (), (base::internal::CopyMode)1> const&)
out/gn-vptr-null/../../base/test/launcher/unit_test_launcher.cc:206
    #19 0xa58948 in base::LaunchUnitTests(int, char**, base::Callback<int (), (base::internal::CopyMode)1> const&) out/gn-vptr-null/../../base/test/launcher/unit_test_launcher.cc:445:10
    #20 0x8d8468 in views::ViewsTestSuite::RunTests() out/gn-vptr-null/../../ui/views/views_test_suite.cc:32:10
    #21 0x819e1a in main out/gn-vptr-null/../../ui/views/run_all_unittests_main.cc:8:44
    #22 0x7f3d795def44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287
    #23 0x495590 in _start (/usr/local/google/home/krasin/chr19/src/out/gn-vptr-null/views_unittests+0x495590)

[1/1] FocusManagerTest.AdvanceFocusStaysInWidget (CRASHED)

So, we got removed == NULL here:
https://cs.chromium.org/chromium/src/ui/views/focus/focus_manager.cc?q=ui/views/focus/focus_manager.cc:520&sq=package:chromium&l=520

void FocusManager::ViewRemoved(View* removed) {
  // If the view being removed contains (or is) the focused view,
  // clear the focus.  However, it's not safe to call ClearFocus()
  // (and in turn ClearNativeFocus()) here because ViewRemoved() can
  // be called while the top level widget is being destroyed.
  if (focused_view_ && removed->Contains(focused_view_))
    SetFocusedView(NULL);
}

Taking a closer look...
Cc: sky@chromium.org
This is not a recent regression, and it's not clear to me if we can guarantee removed != NULL. Speculative fix: https://codereview.chromium.org/2036193003

I don't particularly like the fix as may mask a bigger problem. Leaving to the code owners to decide.
Owner: sky@chromium.org
The fix (as I suspected) is the right. The sky's comment from the review:

"""
This code shouldn't have to check for a null supplied view. This code should
have a DCHECK(removed) and callers shouldn't supply null.
"""

Given that I have zero knowledge of that code, tentatively reassigning the bug to sky, but I expect that the proper owner for the bug is someone else. Please, help me to find them.
So, I was curious and made a simple change that adds the DCHECK into  FocusManager::ViewRemoved. Then I ran trybots on it to see if passing a NULL into this function is an isolated case or a norm:

https://codereview.chromium.org/2047083002/

It seems to be a norm. Almost all tests which deal with views are affected on all (or almost all) OSes.

Scott, do you have a suggestion how to proceed here? If we're willing to accept the fact it happens, my change (https://codereview.chromium.org/2036193003/) should be the one. If it needs to be fixed, do you have an idea how to do it, or do you know a better owner for the bug?
oh, actually, it's more interesting than that. While it's a norm for NULL to be passed into FocusManager::ViewRemoved, it's only if focused_view_ is also NULL, thus the call is not happening.

I've updated my exploratory CL to test that and found out that FocusManagerTest.AdvanceFocusStaysInWidget is realy special:
https://codereview.chromium.org/2047083002/

The possible second candidate is ViewTest.HandleAccelerator which only fails under Chrome OS:
https://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_chromeos_rel_ng/builds/224938


ViewTest.HandleAccelerator really has some Chrome OS specific code:
https://cs.chromium.org/chromium/src/ui/views/view_unittest.cc?q=HandleAccelerator+viewtest&sq=package:chromium&dr=CSs&l=2129

#if defined(USE_AURA) && !defined(OS_CHROMEOS)
  // When a non-child view is not active, it shouldn't handle accelerators.
  EXPECT_FALSE(widget->IsActive());
  EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
  EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]);
#endif

...

#if defined(USE_AURA) && !defined(OS_CHROMEOS)
  // When a child view is not in focus, its parent should handle accelerators.
  child_view->accelerator_count_map_[return_accelerator] = 0;
  view->accelerator_count_map_[return_accelerator] = 0;
  child_focus_manager->ClearFocus();
  EXPECT_FALSE(child_view->GetWidget()->IsActive());
  EXPECT_TRUE(child_focus_manager->ProcessAccelerator(return_accelerator));
  EXPECT_EQ(0, child_view->accelerator_count_map_[return_accelerator]);
  EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
#endif

which deals with the focus. So, not completely a surprise.
FocusManagerTest.AdvanceFocusStaysInWidget failure is related to the destruction of the widget after those two lines:
https://cs.chromium.org/chromium/src/ui/views/focus/focus_manager_unittest.cc?q=AdvanceFocusStaysInWidget&sq=package:chromium&l=912

delegate->set_should_advance_focus_to_parent(true);
GetFocusManager()->AdvanceFocus(true);

Worth noting that set_should_advance_focus_to_parent method is only used once across the whole Chrome codebase: in this test. Unless there's a code outside of what the code search can find that uses it, we may consider deleting this method altogether.

This does not explain the mystery, and it also does not explain ViewTest.HandleAccelerator failure, so I will keep digging.
This fix handles both failures: https://codereview.chromium.org/2047083002/
It's a bit better than a previous one and also adds a DCHECK to warn us, if this happens again.
Project Member

Comment 10 by bugdroid1@chromium.org, Jun 16 2016

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/3f785a8c6d9e355eef6ea0b09c6df1eaedc850f4

commit 3f785a8c6d9e355eef6ea0b09c6df1eaedc850f4
Author: krasin <krasin@google.com>
Date: Thu Jun 16 16:45:22 2016

Do not allow NULL to be passed into FocusManager::ViewRemoved, when focused_view_ != NULL.

This could happen when a top view is focused and it's being destroyed.

BUG= 617305 

Review-Url: https://codereview.chromium.org/2047083002
Cr-Commit-Position: refs/heads/master@{#400174}

[modify] https://crrev.com/3f785a8c6d9e355eef6ea0b09c6df1eaedc850f4/ui/views/focus/focus_manager.cc
[modify] https://crrev.com/3f785a8c6d9e355eef6ea0b09c6df1eaedc850f4/ui/views/widget/widget.cc

Status: Fixed (was: Untriaged)
UBSan Vptr bot is now green!
https://build.chromium.org/p/chromium.fyi/builders/UBSanVptr%20Linux/builds/529

Sign in to add a comment