Qt SQL 和 QOCI 驱动程序(Oracle OCI 驱动程序)的内存泄漏

问题描述 投票:0回答:1

在下面的C++ 17程序中,不同的静态分析器在关闭和打开数据库时显示内存泄漏。

我写了一个最小的可重现示例,显示了实际代码似乎泄漏的部分。

更改 SQL 驱动程序似乎可以减少内存泄漏检测,但仍然有一些。

这是之后的内存泄漏报告示例:

main.cpp

#include <mcheck.h>

#include <iostream>
#include <memory>

#include <QSqlDatabase>

auto getDb() -> QSqlDatabase {
    QSqlDatabase db = QSqlDatabase::addDatabase("QOCI");

    db.setDatabaseName("db");
    db.setHostName("123.456.789");
    db.setUserName("userName");
    db.setPassword("password");
    db.setPort(1234);
    db.setConnectOptions("OCI_ATTR_PREFETCH_ROWS=100;OCI_ATTR_PREFETCH_MEMORY=0");

    return db;
}

auto main(int argc, char** argv) -> int {
    if (argc != 4) {
        std::cerr << "Usage: " << argv[0] << " ITERATIONS WITH_TRACE USE_FIX" << std::endl;
        return EXIT_FAILURE;
    }

    const long ITERATIONS = std::strtol(argv[1], nullptr, 10);
    const bool TRACE      = std::strtol(argv[2], nullptr, 10) == 1;
    const bool USE_FIX    = std::strtol(argv[3], nullptr, 10) == 1;
    
    QSqlDatabase db = getDb();

    std::cout << "Running test loop of " << ITERATIONS << " iterations ...\n" << std::endl;

    if (TRACE) {
        std::cout << "start mtrace" << std::endl;
        mtrace();
    }

    for (int i = 0; i < ITERATIONS; ++i) {
        if (i % 100 == 0) { std::cout << "i=" << i << std::endl; }

        // Refresh the connection
        if (db.isOpen()) { 
            db.close();
            
            // Possible fix
            if (USE_FIX) {
                QSqlDatabase::removeDatabase("db");
                db = getDb();
                
            }
        }

        db.open();
        // End refresh
    }

    if (TRACE) { muntrace(); }
    
    QSqlDatabase::removeDatabase("db");

    return EXIT_SUCCESS;
}

记忆博士

~~Dr.M~~ Error #829: UNADDRESSABLE ACCESS: reading 0xffffffffff5ff080-0xffffffffff5ff084 4 byte(s)
~~Dr.M~~ # 0 linux-vdso.so.1!?                  +0x0      (0x00007ffc4f452bcf <linux-vdso.so.1+0xbcf>)
~~Dr.M~~ # 1 libclntshcore.so.12.1!sLdiGetDate          
~~Dr.M~~ # 2 libclntsh.so.12.1!dbglWriteLogCommon
~~Dr.M~~ # 3 libclntsh.so.12.1!dbgrlWriteAlertDetail
~~Dr.M~~ # 4 libclntsh.so.12.1!dbgrlWriteAlertText
~~Dr.M~~ # 5 libclntsh.so.12.1!nlddwrtlog       
~~Dr.M~~ # 6 libclntsh.so.12.1!nldsadrvfp       
~~Dr.M~~ # 7 libclntsh.so.12.1!nldsfprintf      
~~Dr.M~~ # 8 libclntsh.so.12.1!niqlce1          
~~Dr.M~~ # 9 libclntsh.so.12.1!niotns           
~~Dr.M~~ #10 libclntsh.so.12.1!osncon           
~~Dr.M~~ #11 libclntsh.so.12.1!kpuadef          
~~Dr.M~~ #12 libclntsh.so.12.1!upiini           
~~Dr.M~~ #13 libclntsh.so.12.1!kpuatch          
~~Dr.M~~ #14 libclntsh.so.12.1!OCIServerAttach  
~~Dr.M~~ #15 libqsqloci.so!_init                +0x4e16   (0x00007fd42669b12f <libqsqloci.so+0xb12f>)
~~Dr.M~~ #16 libQt5Sql.so.5!QSqlDatabase::open  +0x30     (0x00007fd428db3ce1 <libQt5Sql.so.5+0x14ce1>)
~~Dr.M~~ #17 main                                [/opt/select/gitlab-runner/francelis/frlis_DbCore/src/MemoryLeakTest.cpp:56]

...

~~Dr.M~~ ERRORS FOUND:
~~Dr.M~~     101 unique,   578 total unaddressable access(es)
~~Dr.M~~     759 unique,  5364 total uninitialized access(es)
~~Dr.M~~       0 unique,     0 total invalid heap argument(s)
~~Dr.M~~       4 unique,     8 total warning(s)
~~Dr.M~~       2 unique,     2 total,  41616 byte(s) of leak(s)
~~Dr.M~~       1 unique,     1 total, 139648 byte(s) of possible leak(s)
~~Dr.M~~ ERRORS IGNORED:
~~Dr.M~~     328 unique,   552 total, 854604 byte(s) of still-reachable allocation(s)
~~Dr.M~~          (re-run with "-show_reachable" for details)

mtrace

= Start
@ /opt/Qt5/lib/libQt5Core.so.5:(_ZN10QArrayData8allocateEmmm6QFlagsINS_16AllocationOptionEE+0x59)[0x7fa2d5f16fe9] + 0xbb8f20 0x4e
@ /opt/Qt5/lib/libQt5Core.so.5:(_ZN9QListData11detach_growEPii+0x45)[0x7fa2d5f643a5] + 0xbb90b0 0x20
@ /opt/Qt5/lib/libQt5Core.so.5:(_ZN10QArrayData8allocateEmmm6QFlagsINS_16AllocationOptionEE+0x59)[0x7fa2d5f16fe9] + 0xbb9020 0x4e
@ /opt/Qt5/lib/libQt5Core.so.5:(_ZN10QArrayData8allocateEmmm6QFlagsINS_16AllocationOptionEE+0x59)[0x7fa2d5f16fe9] + 0xbb8fd0 0x46
@ /opt/Qt5/lib/libQt5Core.so.5:(_ZN10QArrayData8allocateEmmm6QFlagsINS_16AllocationOptionEE+0x59)[0x7fa2d5f16fe9] + 0xbb8ef0 0x20
@ /opt/Qt5/plugins/sqldrivers/libqsqloci.so:[0x7fa2d6489c3f] - 0xbb8ef0
@ /opt/Qt5/plugins/sqldrivers/libqsqloci.so:[0x7fa2d6489c47] - 0xbb8fd0
...
@ /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1:(nlnvmal+0x1a)[0x7fa2d32d9fda] + 0xbded30 0x38
@ /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1:(nlnvmal+0x1a)[0x7fa2d32d9fda] + 0xbded70 0x5
@ /lib64/ld-linux-x86-64.so.2:[0x7fa2d643b16e] + 0xbe2b10 0x90
@ /lib64/libc.so.6:(__strdup+0x1a)[0x7fa2d506cb8a] + 0xbe2bb0 0x28
@ /lib64/libnss_myhostname.so.2:(_nss_myhostname_gethostbyname4_r+0x1e3)[0x7fa2c6a032b3] - 0xbe2bb0
@ /lib64/libc.so.6:(__resolv_context_put+0x45)[0x7fa2d50f08f5] - 0xbdf320
@ /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1:[0x7fa2d32d948d] - 0xbdf300
...
= End
...

valgrind

==649== Memcheck, a memory error detector
==649== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==649== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==649== Command: bin/MemoryLeakTest 1 0
==649== 
==649== Conditional jump or move depends on uninitialised value(s)
==649==    at 0xB3AC860: lmmmalloc (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB18EEC5: lmmcis (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB194589: lpmpali (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB19413C: lpmloadpkg (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB17609A: lfvLoadPkg (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB175D45: lfvSetShlMode (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB17573F: lfvini1 (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB175384: lfvinit (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0x7FB1768: kpummpin (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x7A3C6A3: kpuenvcr (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x79F370E: OCIEnvCreate (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x41DDF90: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649== 
==649== Conditional jump or move depends on uninitialised value(s)
==649==    at 0xB3AC88F: lmmmalloc (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB18EF8B: lmmcis (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB194589: lpmpali (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB19413C: lpmloadpkg (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB17609A: lfvLoadPkg (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB175D45: lfvSetShlMode (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB17573F: lfvini1 (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB175384: lfvinit (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0x7FB1768: kpummpin (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x7A3C6A3: kpuenvcr (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x79F370E: OCIEnvCreate (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x41DDF90: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649== 
==649== Use of uninitialised value of size 8
==649==    at 0xB114130: lxgt2u (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB3A0F47: lxgcnvb (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB3996B0: lxgcnv (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0x87FD6CA: kpuecs2u (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0xA33AADC: OCIErrorGet (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x41DB993: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x41DC0EF: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x41DF071: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x4041CE0: QSqlDatabase::open() (in /opt/Qt5/lib/libQt5Sql.so.5.10.1)
==649==    by 0x402C8E: main (MemoryLeakTest.cpp:56)
==649== 
==649== Conditional jump or move depends on uninitialised value(s)
==649==    at 0xB1141AD: lxgt2u (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB3A0F47: lxgcnvb (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0xB3996B0: lxgcnv (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0x87FD6CA: kpuecs2u (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0xA33AADC: OCIErrorGet (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x41DB993: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x41DC0EF: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x41DF071: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x4041CE0: QSqlDatabase::open() (in /opt/Qt5/lib/libQt5Sql.so.5.10.1)
==649==    by 0x402C8E: main (MemoryLeakTest.cpp:56)
==649== 
==649== Conditional jump or move depends on uninitialised value(s)
==649==    at 0x8604854: __intel_sse2_strncpy (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0xB176387: lfvpkgname (in /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1)
==649==    by 0x7FB1795: kpummpin (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x7A3C6A3: kpuenvcr (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x79F370E: OCIEnvCreate (in /usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1)
==649==    by 0x41DDF90: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x41E8712: ??? (in /opt/Qt5/plugins/sqldrivers/libqsqloci.so)
==649==    by 0x4043851: ??? (in /opt/Qt5/lib/libQt5Sql.so.5.10.1)
==649==    by 0x4043D60: QSqlDatabase::addDatabase(QString const&, QString const&) (in /opt/Qt5/lib/libQt5Sql.so.5.10.1)
==649==    by 0x4027E8: main (MemoryLeakTest.cpp:28)
...
==649== LEAK SUMMARY:
==649==    definitely lost: 128 bytes in 2 blocks
==649==    indirectly lost: 41,488 bytes in 8 blocks
==649==      possibly lost: 139,648 bytes in 3 blocks
==649==    still reachable: 763,863 bytes in 332 blocks
==649==         suppressed: 0 bytes in 0 blocks
==649== Reachable blocks (those to which a pointer was found) are not shown.
==649== To see them, rerun with: --leak-check=full --show-leak-kinds=all

即使使用

USE_FIX
,也会显示内存错误。如何消除这些错误?

c++ oracle qt driver oracle-cloud-infrastructure
1个回答
0
投票

用pmap命令监控程序进程后就ok了

watch -n 1 "pmap ${WATCH_PID} | awk '/total/{print \$2}'"

在运行程序的 docker 容器内,使用的内存在 10k 次迭代期间保持不变,因此我假设该程序实际上不会泄漏...(我们未能针对主代码的泄漏部分)

感谢 @ibre5041 评论,由于 Oracle OCI 库的构建方式,所有静态分析器内存泄漏报告都愿意误报。

© www.soinside.com 2019 - 2024. All rights reserved.