https://bugs.kde.org/show_bug.cgi?id=433402

            Bug ID: 433402
           Summary: KJobsTest in test suite flags undefined behavior
                    sanitizer
           Product: frameworks-kcoreaddons
           Version: 5.79.0
          Platform: Compiled Sources
                OS: Linux
            Status: REPORTED
          Severity: minor
          Priority: NOR
         Component: general
          Assignee: mp...@kde.org
          Reporter: mp...@kde.org
                CC: kdelibs-b...@kde.org
  Target Milestone: ---

SUMMARY

The autotest "kjobtest" causes errors and warning messages about use of
undefined behavior. This makes it problematic to run the test suite under
aggressive compiler sanitizing because it will then be expected to fail, which
reduces the viability of using sanitizers to catch bugs.

STEPS TO REPRODUCE
1. Ensure that kcoreaddons is configured to build autotests by CMake.

2. Compile kcoreaddons with Address Sanitizer (asan) and Undefined Behavior
Sanitizer (ubsan). I used in my kdesrc-buildrc:

options kcoreaddons
    cmake-options -DBUILD_TESTING:BOOL=ON
    cxxflags -fsanitize=address -fsanitize=undefined -ggdb
end options

***NOTE*** if you do this only for kcoreaddons and install the result, your
other Qt/KDE applications may fail to launch. I believe this is due to
something about the Qt platform plugin because running something like
"XDG_CURRENT_DESKTOP=GNOME assistant" succeeds in this case when just running
"assistant" would not.

2. Go to kcoreaddons build directory and run ./bin/kjobtest

OBSERVED RESULT

user@domain /kdesrc/build/kf5/frameworks/kcoreaddons $ ./bin/kjobtest 
********* Start testing of KJobTest *********
Config: Using QtTest library 5.15.1, Qt 5.15.1 (x86_64-little_endian-lp64
shared (dynamic) release build; by GCC 10.2.0), gentoo unknown
PASS   : KJobTest::initTestCase()
PASS   : KJobTest::testEmitResult(no error)
PASS   : KJobTest::testEmitResult(error no text)
PASS   : KJobTest::testEmitResult(error with text)
PASS   : KJobTest::testProgressTracking()
PASS   : KJobTest::testExec(no error)
PASS   : KJobTest::testExec(error no text)
PASS   : KJobTest::testExec(error with text)
PASS   : KJobTest::testKill(killed with result)
PASS   : KJobTest::testKill(killed quietly)
/kdesrc/src/kf5/frameworks/kcoreaddons/autotests/kjobtest.cpp:439:5: runtime
error: downcast of address 0x603000003be0 which does not point to an object of
type 'TestJob'
0x603000003be0: note: object is of type 'KJob'
 02 00 00 45  b8 a2 71 5f 1c 7f 00 00  20 24 00 00 80 60 00 00  a0 24 00 00 80
60 00 00  00 00 00 00
              ^~~~~~~~~~~~~~~~~~~~~~~
              vptr for 'KJob'
PASS   : KJobTest::testDestroy()
PASS   : KJobTest::testEmitAtMostOnce(Start-Start-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(Start-KillQuietly-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(Start-KillVerbosely-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-Start-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-KillQuietly-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-KillVerbosely-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-Start-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-KillQuietly-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-KillVerbosely-autoDelete)
PASS   : KJobTest::testEmitAtMostOnce(Start-Start)
PASS   : KJobTest::testEmitAtMostOnce(Start-KillQuietly)
PASS   : KJobTest::testEmitAtMostOnce(Start-KillVerbosely)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-Start)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-KillQuietly)
PASS   : KJobTest::testEmitAtMostOnce(KillQuietly-KillVerbosely)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-Start)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-KillQuietly)
PASS   : KJobTest::testEmitAtMostOnce(KillVerbosely-KillVerbosely)
PASS   : KJobTest::testDelegateUsage()
PASS   : KJobTest::testNestedExec()
PASS   : KJobTest::cleanupTestCase()
Totals: 32 passed, 0 failed, 0 skipped, 0 blacklisted, 302ms
********* Finished testing of KJobTest *********

=================================================================
==131922==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 2 object(s) allocated from:
    #0 0x7f1c60269b48 in __interceptor_realloc
/var/tmp/portage/sys-devel/gcc-10.2.0-r5/work/gcc-10.2.0/libsanitizer/asan/asan_malloc_linux.cpp:164
    #1 0x7f1c5e0d5f42 in d_growable_string_resize
/var/tmp/portage/sys-devel/gcc-10.2.0-r5/work/build/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/cp-demangle.c:4036
    #2 0x7f1c5e0d5f42 in d_growable_string_append_buffer
/var/tmp/portage/sys-devel/gcc-10.2.0-r5/work/build/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/cp-demangle.c:4060
    #3 0x7f1c5e0d5f42 in d_growable_string_callback_adapter
/var/tmp/portage/sys-devel/gcc-10.2.0-r5/work/build/x86_64-pc-linux-gnu/libstdc++-v3/libsupc++/cp-demangle.c:4077

SUMMARY: AddressSanitizer: 16 byte(s) leaked in 2 allocation(s).


EXPECTED RESULT

I expected a result as above but without warnings from the compiler about a
downcast to an improper type.

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Gentoo Linux 5.11.0-rc7-00115-gc6d8570e4d64 (64-bit) on X11
KDE Plasma Version: 5.21.80
KDE Frameworks Version: 5.80.0
Qt Version: 5.15.1

ADDITIONAL INFORMATION

The test case admits the undefined behavior going on (in
KJobTest::slotFinished):

    // qobject_cast and dynamic_cast to TestJob* fail when finished() signal is
emitted from
    // ~KJob(). The static_cast allows to call the otherwise protected
KJob::isFinished().
    // WARNING: don't use this trick in production code, because
static_cast-ing
    // to a wrong type and then dereferencing the pointer is undefined
behavior.
    // Normally a KJob and its subclasses should manage their finished state on
their own.
    // If you *really* need KJob::isFinished() to be public, request this
access
    // modifier change in the KJob class.
    QVERIFY(static_cast<const TestJob *>(job)->isFinished());

slotFinished isn't always called from the KJob destructor in this test case but
it is at least once.

However if you look at the KJob API for KJob::isFinished() [1] it is clear that
this function is only helpful to KJob itself, not to external classes or any
subclasses, in the context of being checked from the KJob destructor. Since the
method is protected it can only be called by KJob or subclasses, but by the
time KJob::~KJob() runs, there are no more subclasses to use it.

So I'm not sure that there is value in double-checking that KJob::isFinished()
operates successfully in the narrow use case of KJob::~KJob().

[1]
https://api.kde.org/frameworks/kcoreaddons/html/classKJob.html#a67b6c63fc5eb7bd31234960e7a5487d9

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to