How to find all global variables in C++ source code, DLL or any file created by the VC++ compiler?
Asked Answered
T

8

26

I'm making my application thread-safe. One of the steps is to synchronize access or eliminate usages of global variables. I'm using Visual Studio. I can't find any good way to find all global variables in my codebase. It's impossible to create a good text search pattern and I can't find any helpful tool. Do you guys know any good way to do that? It could be a source code analysis tool or a binary file analyzer.

Truda answered 15/9, 2011 at 11:45 Comment(4)
What's wrong with "static but not const" expressed in your favourite script language as a search pattern?Potage
That finds class- and function-level statics, too. Good thing in this case, as they also need synchronization, but it doesn't precisely answer the question from the title.Mundy
If you have globals they are used across translation units, thus you will have extern declarations in header files; finding them should be easy since the extern keyword not followed by a quoted string in practice is used only for this.Suzan
Matteo Italia, not exact. Global variable is extern by default (in C/C++); and two declaration with same name, type and initializer (if any) will be merged by linker.Lest
R
15

This could help:

  1. Open the project in visual studio.
  2. Open 'Class View' of the project
  3. Under the project title, you will find 'Global Functions and Variable'.

I have checked this with Visual Studio 2010 and above.

Edit: As suggested by Ajay in comments, you could also categorize items in groups. For grouping items:

  1. In class view, right click on project title
  2. Select `Group By Object/Member Type'
  3. Select the required tree like variables or structures or enums etc.
Rader answered 11/12, 2015 at 9:47 Comment(1)
It does help! Additional tip: After launching 'Class View', nightstick and select "Group By Member Type", and then select "Variables" tree.Luminesce
D
8

One option might be letting the linker generate a map file (/MAP in Visual Studio).

You will get a .map file for each binary with two sections:

A table of segments

 Start         Length     Name                   Class
 0001:00000000 00010000H .textbss                DATA
 0002:00000000 000034b4H .text                   CODE
 0003:00000000 00000104H .CRT$XCA                DATA
 0003:00000104 00000104H .CRT$XCAA               DATA
 0003:00000208 00000104H .CRT$XCZ                DATA
 0003:0000030c 00000104H .CRT$XIA                DATA
 ...

A list of symbols (functions and data)

  Address         Publics by Value              Rva+Base       Lib:Object

 0000:00000000       ___safe_se_handler_count   00000000     <absolute>
 0000:00000000       ___safe_se_handler_table   00000000     <absolute>
 0000:00000000       ___ImageBase               00400000     <linker-defined>
 0001:00000000       __enc$textbss$begin        00401000     <linker-defined>
 0001:00010000       __enc$textbss$end          00411000     <linker-defined>
 0002:000003a0       _wmain                     004113a0 f   console4.obj
 ...

You can tell apart the functions from variables by the "CODE" / "DATA" designaiton in the segment list.

Advantage: You will get all symbols, even those in libraries, that were not removed by the Linker.

Disadvanatge: You will get all symbols, even those in libraries, that were not removed by the Linker. I don't know of any tool that does the code/data separation automatically.

Deerstalker answered 15/9, 2011 at 12:20 Comment(3)
Given that you can find the globals there in the segments table, how can you determine which source files they are coming from? Thanks.Jules
@NHDaly: there is no explicit information in the map file (could be retrieved from the debug info), but usually the object file is enough, e.g. console4.obj virtually always comes from a console4.cpp.Deerstalker
thanks, agreed. I was getting this information through dumpbin, but that doesn't work on .obj files. I will try this option instead. Can you specify /MAP when compiling with the Visual Studio Console Tools rather than the application itself? Thanks!Jules
L
3

I know the http://code.google.com/p/data-race-test/wiki/ThreadSanitizer program (product of google) which can work in Windows and on compiled code. It is dynamic instrumentation program (like valgrind or bit like qemu/virtualbox), which add some checks to memory accesses. It will try to find some threading problems. You can just run your program under control of threadsanitizer. There will be slowdown from dynamic translation and from instrumentation code (up to 20x-50x times slower). But Some problems will be detected automatically.

It also allows you to annotate some custom synchronization functions in source code.

Wiki of program has links to other thread-race detectors: http://code.google.com/p/data-race-test/wiki/RaceDetectionLinks

Lest answered 15/9, 2011 at 11:52 Comment(0)
T
2

cppclean is a static analysis tool that can help you. From the documentation:

cppclean finds global/static data that are potential problems when using threads.

A simple example with a static local variable and a global variable follows.

./example.h:

void foo();

./example.cpp:

#include "example.h"

int globalVar = 42;

void foo(){
    static int localStatic = 0;
    localStatic++;
}

Open a terminal and run cppclean as follows:

$ cppclean --include-path . example.cpp
example.cpp:3: static data 'globalVar'
example.cpp:6: static data 'localStatic'

Unfortunately, cppclean has some parsing issues and bugs. However, these issues are pretty rare, and affected below a percent of all code I've tested.

Typeface answered 20/7, 2019 at 9:17 Comment(0)
S
2

You can try CppDepend by using its code query language

from  f in Fields where f.IsGlobal select f

enter image description here

Spate answered 22/7, 2019 at 10:57 Comment(0)
P
1

Maybe dumpbin tool will help here. You can run it with /SYMBOLS key to display the COFF symbol table and look for External symbols - global variables should be in this list. DUMPBIN /SYMBOLS.

Pacify answered 15/9, 2011 at 12:39 Comment(0)
M
0

You all are making this too complicated.

1. Copy the code of each of your files (one at a time separate from the others) to a string or a wide string or etc. and then parse out everything that is from "{" to "}" uninclusive. Save the result to an exterior file. After the first time, then append to that file.

2. Even if you have 1,000 lines total of what is left after all that parsing, in that are all of your globals (depending upon how you created the globals). If you created them via a namespace, etc. then go back and parse for that. I doubt that most programmers will have 1,000 globals, but for some applications it might be what they use. If you do not have too many at that point then manually edit that text file of the results.

I have found that maybe 90+ % of the answers on this site are bloated with far too much complexity that just eats up cpu time and memory space. Keep it simple.

You might find it handy to have a globals.h file which you load early and keep most or all of you globals there. It looks like time to do a lot of clean up.

Mesencephalon answered 13/9, 2022 at 8:55 Comment(4)
Re "parse out everything that is from "{" to "}" uninclusive": The source code might be much more complex than that, especially if macros are involved.Steam
The Unix-Haters handbook explicitly calls this out: 'Once we were talking to a Unix programmer about how nice it would be to have a utility that could examine a program and then answer questions such as: "What functions call function foo?" or "Which functions modify the global variable bar?" He agreed that it would be useful and then observed that, "You could write a program like that."Karimakarin
To be fair, the reason he said "You could write a program like that" instead of actually writing the program is that some properties of the C language and the Unix "Programming Environment" combine synergistically to make writing such a utility a pain of epic proportion. You may think we exaggerate, and that this utility could be easily implemented by writing a number of small utility programs and then piping them together, but we’re not, and it can’t.'Karimakarin
Not sure if I understand the "parse out everything that is from "{" to "}" uninclusive" bit. It sounds like you're excluding code in a namespace. Most, if not all, global variables should be in a namespace.Gloss
K
0

In clang-query all global variables can be listed using

match varDecl(hasGlobalStorage())

For a more complicated example, to find all global variables that are pointers to my_type,

match varDecl(hasGlobalStorage(), hasType(pointerType(pointee(hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(hasName("my_type")))))))))

This finds all

  • Traditional global variables
  • static variables inside functions
  • static member variables of classes

See Running clang-query only on input files for how to limit the results.

Note that if a global variable occurs in a template that is never instantiated, the above will list it, even though there isn't actually such a global variable in the compiled code.

Karimakarin answered 30/4, 2024 at 6:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.