【问题标题】:error with sprintf statement using a double (buffer overrun?)使用双精度的 sprintf 语句出错(缓冲区溢出?)
【发布时间】:2023-03-27 21:59:01
【问题描述】:

我遇到了错误 sprintf 语句。我添加了一个 printf 命令来帮助调查,似乎我的一个双打没有被理解(printf 输出一串无意义的数字,其中应该是 %3.1f。)但是,双打第一次被正确解释它在 printf 语句中调用。通过将大小名称从 120 增加到 320,段错误确实消失了。但是双精度仍然没有被正确解释,即它仍然输出一串无意义的数字,一个简单的 %3.1f 应该是。我无法弄清楚我做错了什么。有任何想法吗?代码的最小测试用例版本和下面发布的错误消息。

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <sstream>
    #include <strstream>
    #include <vector>

    using namespace std;


    void Back_Subt_beta()
    {

        int resonances = 4;
        char name[320];
        double rpos[66];
        double rbinmin[66];
        double rbinmax[66];

        ifstream binedgein;
        binedgein.open("binedges.dat");
        if (binedgein.is_open()) {
            cout << "data file opens" << endl;
            }
        for (int vline=1; vline<=4; vline++)
        {
            binedgein >> var1 >> var2 >> var3;
            rpos[vline-1] = var1;
            rbinmin[vline-1] = var2;
            rbinmax[vline-1] = var3;
        }
        binedgein.close();


        for (int m=2; m<=7; m++)
        {
            for (int j=0; j<resonances; j++)
            {
                printf("resonance%0#7.2feV/gammas_%3.1feV_Mcl%i", rpos[j],rpos[j],m);
                sprintf(name,"resonance%0#7.2feV/gammas_%3.1feV_Mcl%i",rpos[j],rpos[j],m);
            }
        }
        exit();
    }

和文件 binedges.dat

16.2      16.0      16.5
38.75     38.25     39.25
44.5      43.5      45.5
55.25     54.75     55.75

还有错误:

Processing Back_Subt_beta.C...
data file opens

 *** Break *** segmentation violation
resonance0016.20eV/gammas_917241681885348612676436160464141677586357964289319457240620564649334534999701390133785258335880600276911524435084428436805391368574132924760441246552362332456319675531264.0eV_Mcl16(no debugging symbols found)
Using host libthread_db library "/lib/tls/libthread_db.so.1".
Attaching to program: /proc/7689/exe, process 7689
[Thread debugging using libthread_db enabled]
[New Thread -1208284352 (LWP 7689)]
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.
(no debugging symbols found)...done.

0x006dd7a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1  0x014d3533 in __waitpid_nocancel () from /lib/tls/libc.so.6
#2  0x0147c869 in do_system () from /lib/tls/libc.so.6
#3  0x00962b8d in system () from /lib/tls/libpthread.so.0
#4  0x00bebc8e in TUnixSystem::Exec () from /usr/local/root/lib/libCore.so
#5  0x00be6dfb in TUnixSystem::StackTrace () from /usr/local/root/lib/libCore.so
#6  0x00be5c53 in TUnixSystem::DispatchSignals () from /usr/local/root/lib/libCore.so
#7  0x00bebf4d in SigHandler () from /usr/local/root/lib/libCore.so
#8  0x00be0590 in sighandler () from /usr/local/root/lib/libCore.so
#9  <signal handler called>
#10 0x014b1d0a in strcmp () from /lib/tls/libc.so.6
#11 0x003033be in G__searchvariable () from /usr/local/root/lib/libCint.so
#12 0x002f9514 in G__getvariable () from /usr/local/root/lib/libCint.so
#13 0x0021de97 in G__getitem () from /usr/local/root/lib/libCint.so
#14 0xbfeb89dc in ?? ()
#15 0x0021c633 in G__getexpr () from /usr/local/root/lib/libCint.so
#16 0x00000048 in ?? ()
#17 0x002e9bc8 in G__letvariable () from /usr/local/root/lib/libCint.so
#18 0xbfeb987c in ?? ()
Root > Function Back_Subt_beta() busy flag cleared

【问题讨论】:

  • 您确定问题不在于对无效数组位置的访问?
  • 我不确定你的意思。但是我使用 cout 语句来确定段错误发生在该 sprintf 行,而不是在我尝试获取 sprintf 命令中命名的文件之后。所以我之前插入了 printf 语句,看看 sprintf 在做什么。
  • 字符串长度应小于 40 个字符。我认为这没关系......但是:增加 name[320] 的大小确实会阻止段错误。但是双精度仍然没有被正确解释,即它仍然输出一串无意义的数字,一个简单的 %3.1f 应该是。
  • 您确实应该使用 snprintf,这样它只会复制您需要的内容。可能是 char 数组已满。

标签: c++ arrays segmentation-fault printf


【解决方案1】:

我认为您的问题是 char 数组 name 只有 120 个字节,但是您的 sprintf 语句溢出了该缓冲区。将 char 缓冲区的大小从 120 字节增加到更大的值。更好的是,使用snprintf() 而不是sprintf()

【讨论】:

  • 将其增加到 320,segfault 停止,但 sprintf 的结果仍然是乱码。我从未使用过 snprintf,但我现在会研究一下...
  • 我想使用 snprintf,但不幸的是我在我的系统上找不到合适的头文件(而且我不是管理员。)我能够通过拆分暂时解决问题sprintf 分成两个不同的,然后将它们组合起来。这很难看,但它是我可以立即使用的唯一可行的解​​决方案。我看看以后能不能找到那些头文件。
  • @neverskipbreakfast:你试过#include &lt;cstdio&gt;吗?
【解决方案2】:

您正在溢出 name 字符数组,该数组仅是 120 字符。最好使用std::string namestr,然后在填充name 时使用str.c_str()

【讨论】:

    【解决方案3】:

    我想知道那个数字是多少,所以我这样做了:

    $ python
    Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
    [GCC 4.6.1] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> x = 917241681885348612676436160464141677586357964289319457240620564649334534999701390133785258335880600276911524435084428436805391368574132924760441246552362332456319675531264.0
    >>> import struct
    >>> struct.pack('<d', x)
    'resonanc'
    

    所以原来的错误肯定是你的字符串覆盖了缓冲区造成的。如果您得到不同的垃圾值,请尝试查看实际位,也许您会弄明白。

    【讨论】:

    • 有趣!因此,即使我将 char 字符串的长度增加到 name[500],当我计算名称时,我仍然会得到相同的垃圾值,但没有段错误。有可能500还不够吗?我不了解 sprintf 的局限性吗?同样有趣的是,我在字符串中得到的最后一个变量也不正确。我应该得到类似共振0016.00eV/gammas_16.0eV_Mcl2的东西,但我得到了共振0016.00eV/gammas_(garbage)eV_Mcl16。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 2010-11-11
    相关资源
    最近更新 更多