1

I have a somewhat large project that I am working on and I've discovered that someone added some code something similar to this:

std::cout << std::hex << variable << endl;

Aside from grepping through all the cout calls and manually looking at each one, is there a way to determine which offending cout line left the output stream's base as hex?

It seems that there's many different ways of setting the base so setting a breakpoint on a single function call doesn't seem to work. e.g.:

  • ... << std::hex << ...
  • ... << setbase(16) << ...
  • std::cout.setf ( std::ios::hex, std::ios::basefield );
  • etc.

Is there any quick way i can tell what variable internally libstdc++ is using to store the base variable so i can set a data breakpoint on it?

UPDATE:

After playing around with the code I was finally able to come up with the solution using in part both answers from perreal and Employed Russian. Here is what I did:

First I added the following code inside my program so I could break and step into the function to get the address of the cout flags variable (_M_flags).

std::ios_base::fmtflags f;
f = std::cout.flags();

I set a breakpoint on the second line and stepped into the function and got the following libstdc++ code:

// [27.4.2.2] fmtflags state functions
/**
 *  @brief  Access to format flags.
 *  @return  The format control flags for both input and output
 */
fmtflags
flags() const
{ return _M_flags; }

Unfortunately gdb was unable to print out this variable but by going to the disassembly view I was able to pinpoint the address used by _M_flags:

 x0x84ca2e8 <std::ios_base::flags() const>                push   %ebp
 x0x84ca2e9 <std::ios_base::flags() const+1>              mov    %esp,%ebp
 x0x84ca2eb <std::ios_base::flags() const+3>              mov    0x8(%ebp),%eax
>x0x84ca2ee <std::ios_base::flags() const+6>              mov    0xc(%eax),%eax 
 x0x84ca2f1 <std::ios_base::flags() const+9>              pop    %ebp
 x0x84ca2f2 <std::ios_base::flags() const+10>             ret

0xc(%eax) contained the address of _M_flags.

After I got the address, it was fairly trivial to set a conditional hardware watchpoint on it to see when the hex bit changes and track down the offending code.

It turns out a .so object loaded at runtime via dlopen was the culprit.

I ended up using Boost IO State Savers as referenced by this question to resolve the issue.

4

2 回答 2

2
#include <iostream>
int main() {
    std::ios_base::fmtflags f;
    f = std::cout.flags();
    std::cout << 21 << std::endl;
    std::cout << (f & std::cout.hex) << std::endl;
    std::cout << std::hex << 21 << std::endl;
    f = std::cout.flags();
    std::cout << (f & std::cout.hex) << std::endl;
    return 0;
}

输出

21
0
15
8

因此,您似乎可以将f & std::cout.hex其用作表达式或找出该标志的存储位置std::cout,这可能取决于实现。

于 2013-05-01T23:53:48.397 回答
2

有什么快速的方法可以告诉我glibc内部使用什么变量来存储基本变量,以便我可以在其上设置数据断点?

不:glibc 是一个库,对, 是一个构造C一无所知。你的问题是关于,而不是关于 glibc。std::coutC++libstdc++

查看 libstdc++实现,您似乎希望在std::cout._M_os._M_flags. 但是,由于标志中的各个位在输出操作期间被设置多次,您可能希望使观察点以_S_hex (== 1<<3 == 8)位为条件。

于 2013-05-02T04:31:06.777 回答