I have this code:
// my.h
#ifndef MY_HEADER
#define MY_HEADER
int create_uid();
#endif
// my.cpp
#include "my.h"
static int _next_uid = 0;
int create_uid()
{
return _next_uid++;
}
I want to inline create_uid(), while keeping the _next_uid variable global to the program so the variable is unique.
My questions are:
Can I do this?
Is the inline statement require _next_uid to be visible outside the compilation unit?
Note: This doesn't seems to answer those questions clearly.
Edited after clarifiation of the question.
If you want only a single _next_uid, then simply put the following into your header file:
inline int create_uid()
{
static int _next_uid = 0;
return _next_uid++;
}
Short answer. No. The following code
// my.h
static int _next_uid = 0;
inline int create_uid() {
return _next_uid++;
}
will probably compile, but will result in undefined behaviour if used in more than one translation units. This is because the _next_uid variables are different entities in different translation units. Thus the definitions of create_uid() are also different. However:
If an inline function [...] with external linkage is defined differently in different translation units, the behavior is undefined. [1]
What you can do instead is either use a local scope static variable in the function, like #DanielLangr showed in one of the other answers [1]. This has the disadvantage, that that variable cannot be accessed outside of the function. Alternatively as #wohlstad mentioned in one of the comments, you can use a C++17 inline variable:
// my.h
inline int _next_uid = 0;
inline int create_uid() {
return _next_uid++;
}
Note that this does not define a static variable. Using static and inline will have the same effect as just using static [3], which results in the undefined behaviour I mentioned above.
Inlining a function means per definition, that all the variables it uses must be reachable from the translation unit where it is inlined. This cannot work with a unique static (thus not visible to other TUs) variable.
[1]: https://en.cppreference.com/w/cpp/language/inline
[2]: https://stackoverflow.com/a/72124623/17862371
[3]: https://stackoverflow.com/a/58101307/17862371
Summary:
It doesn't work if you put implementation of inline next_id() to a single c file, which means the function is in a single compile unit. So main cannot find inline next_id(), you'll get the error undefined reference.
It can be compiled if you declare inline next_id() in a shared header file, in which case each compile unit will properly find inline next_id().
In my case, only one instance of this global variable will appear in virtual address space .DATA segment of the process. The output number is continuous.
Example:
Makefile 8:
all:
c++ -c main.cpp
c++ -c second.cpp
c++ -c share.cpp
c++ main.o second.o share.o -o main
clean:
rm -f main.o second.o share.o main
main.cpp 12:
#include <cstdio>
#include "share.hpp"
#include "second.hpp"
int main(){
printf("[main] %d\n", next_id());
consume_id();
printf("[main] %d\n", next_id());
consume_id();
printf("[main] %d\n", next_id());
return 0;
}
second.hpp 1:
void consume_id();
second.cpp 7:
#include <cstdio>
#include "share.hpp"
void consume_id(){
printf("[scnd] %d\n", next_id());
}
share.hpp 4:
#pragma once
int next_id();
share.cpp 7:
static int _next_id = 0;
int next_id()
{
return _next_id++;
}
Result output:
[main] 0
[scnd] 1
[main] 2
[scnd] 3
[main] 4
But if it is changed to:
share.cpp 4:
inline int next_id()
{
return _next_id++;
}
undefined reference to `next_id()'
If changed to
share.hpp 7:
#pragma once
static int _next_id = 0;
inline int next_id()
{
return _next_id++;
}
Works
EDIT:
It seems to be an undefined behavior
I'm using `gcc version 11.2.0 (Ubuntu 11.2.0-19ubuntu1)
IN MY CASE
You will have copies of static int _next_id but only in the object file. In memory there is only one.
objdump -d main > main.s
main.s 143:
00000000000011b3 <_Z7next_idv>:
11b3: f3 0f 1e fa endbr64
11b7: 55 push %rbp
11b8: 48 89 e5 mov %rsp,%rbp
11bb: 8b 05 53 2e 00 00 mov 0x2e53(%rip),%eax # 4014 <_ZL8_next_id>
11c1: 8d 50 01 lea 0x1(%rax),%edx
11c4: 89 15 4a 2e 00 00 mov %edx,0x2e4a(%rip) # 4014 <_ZL8_next_id>
11ca: 5d pop %rbp
11cb: c3 ret
Here function _Z7next_idv only appears in memory for 1 time.
main.s 147:
11bb: 8b 05 53 2e 00 00 mov 0x2e53(%rip),%eax # 4014 <_ZL8_next_id>
The label of _next_id is _ZL8_next_id, only appears in memory for 1 time as well.
Related
I am trying to write a simple plugin system for an application and would like to prevent plugins from stomping on each others symbols, however RTLD_DEEPBIND and RTLD_LOCAL don't seem to be enough when it comes to static class members when they happen to have the same name in different plugins.
I wrote a stripped down example to show what I mean.
I compiled and ran it like this:
g++ -c dumb-plugin.cpp -std=c++17 -fPIC
gcc -shared dumb-plugin.o -o dumb1.plugin
cp dumb1.plugin dumb2.plugin
g++ main.cpp -ldl -o main
./main
And the content of the output file for the second plugin showed that it reused the the class from the first plugin.
How can I avoid this?
EDIT: I compiled the plugin with clang(not main just the plugin) and it worked despite all of the RTLD_DEEPBIND stuff being in main.cpp which was still compiled with g++. It didn't work when the plugin was compiled with gcc 10.3 or 11.1 even when I tried -Bsymbolic. Is this a bug?
If I run readelf on the DSO compiled/linked with clang i see these 2 lines:
21: 00000000000040b0 4 OBJECT UNIQUE DEFAULT 26 _ZN9DumbClass7co[...]_ZN9DumbClass7co[...]
25: 00000000000040b0 4 OBJECT UNIQUE DEFAULT 26 _ZN9DumbClass7co[...]
and with gcc i get:
20: 00000000000040a8 4 OBJECT WEAK DEFAULT 24 _ZN9DumbClass7co[...]
27: 00000000000040a8 4 OBJECT WEAK DEFAULT 24 _ZN9DumbClass7co[...]
with WEAK instead of UNIQUE under the BIND column.
dumb-plugin.cpp:
#include <dlfcn.h>
#include <cstdio>
#include <string>
int global_counter = 0;
static int static_global_counter = 0;
std::string replace_slashes(const char * str) {
std::string s;
for (const char* c = str; *c != '\0'; c++)
s += (*c == '/')?
'#' : *c;
return s;
}
void foo() {}
class DumbClass {
public:
static inline int counter = 0;
};
extern "C" void plugin_func() {
static int static_local_counter = 0;
Dl_info info;
dladdr((void*)foo, &info);
std::string path = "plugin_func() from: " + replace_slashes(info.dli_fname);
auto fp = std::fopen(path.c_str(), "w");
fprintf(fp, "static local counter: %d\n", static_local_counter++);
fprintf(fp, "DumbClass::counter: %d\n", DumbClass::counter++);
fprintf(fp, "global counter: %d\n", global_counter++);
fprintf(fp, "static global counter: %d\n", static_global_counter++);
std::fclose(fp);
}
main.cpp:
#include <dlfcn.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
int main () {
char path1[512], path2[512];
getcwd(path1, 512);
strcat(path1, "/dumb1.plugin");
getcwd(path2, 512);
strcat(path2, "/dumb2.plugin");
auto h1 = dlopen(path1, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
auto h2 = dlopen(path2, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
auto func = (void(*)()) dlsym(h1, "plugin_func");
func();
func = (void(*)()) dlsym(h2, "plugin_func");
func();
}
gcc implements static inline data members (and also static data members of class templates, inline or not, and static variables in inline functions, and perhaps other things as well) as global unique symbols (a GNU extension to the ELF format). There is only one such symbol with a given name per process, by design.
clang implements such things as normal weak symbols. These will not collide when RTLD_LOCAL and RTLD_DEEPBIND are used.
There are several ways to avoid collisions, but all of them require plugin writers to take an action. The best way IMO is to use hidden symbol visibility by default, only opening symbols that are meant to be dlsymd.
I've been struggling with this and so far couldn't make it work. A simple main using botan works fine, but when i put the same code in a unittest it fails.
// keygeneration_test.cpp
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp> // shuold use this one if using dynamic linking
#include <botan\botan.h>
#include <botan\rsa.h>
BOOST_AUTO_TEST_SUITE(keygeneration_suite)
BOOST_AUTO_TEST_CASE(rsa_key_generation)
{
BOOST_TEST_MESSAGE("generating key");
try
{
Botan::LibraryInitializer init;
Botan::AutoSeeded_RNG rng;
rng.reseed(10096);
Botan::RSA_PrivateKey rsaPrivate(rng, 1024);
}
catch (std::exception& e)
{
BOOST_TEST_MESSAGE(e.what());
}
}
BOOST_AUTO_TEST_SUITE_END()
--
// main.cpp
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE cryptography test //module define should be only here, it takes care of creating entry point
#include <boost/test/unit_test.hpp> // should use this one if using dynamic linking
I then tried putting the init in the main entry point like this:
//main.cpp
#define BOOST_TEST_DYN_LINK // Make the exe link dynamically
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp> // should use this one if using dynamic linking
#include <botan\botan.h>
bool init_function()
{
return true;
}
int main(int argc, char* argv[])
{
Botan::LibraryInitializer init;
return boost::unit_test::unit_test_main(&init_function, argc, argv);
}
They both show the same error:
Running 1 test case... unknown location(0): fatal error in
"rsa_key_generation": memory access violation occurred at address
0x00141000, while attempting to read inaccessible data
*** 1 failure detected in test suite "cryptography test" Detected memory leaks! Dumping objects -> {670} normal block at
0x0000000000221380, 16 bytes long. Data: 78 EA 13
00 00 00 00 00 00 00 00 00 00 00 00 00 Object dump complete.
Just for the record, a simple test for compression that i tried or whatever i did works fine, but when i try to create a test with botan initialization it fails no matter what i try.
Edit: I've tried with Qt Test and the same happens. Its is really weird. Has anyone experienced something like this? Could anyone reproduce this?
Found the annoying problem. Code Generation was set to Multi-threaded DEBUG DLL. For some reason changing to Multi-threaded DLL makes it work. I guess maybe because botan was compiled for release. (it would be nice to have a hint or suggestion from the compiler...)
Maybe this has been asked several times but I couldn't find a single question that were focused on static vars storage inside templated functions. I would like to know where statics within templated functions are stored and how what is the compiler doing with them exactly?
I'm going to provide some g++ memory layout just to show why I don't get them.
My first code I cheched was rather simple:
#include <iostream>
using namespace std;
void my_func() {
static int x;
}
int main() {
my_func();
return 0;
}
When I check the memory layout of this program with g++ 4.8.1 I end up with the following sections:
.text: 1845
.data: 620
.bss: 12
Nothing unexpected so far. The uninitialized static variable is stored within the .bss segment. The same goes if I initialize the x variable to 0, while if I initialize it with any non-zero value the; still nothing unexpected:
.text: 1845
.data: 624
.bss: 8
x in this case is stored within the data segment instead of bss. So far so good, so I turned towards my questionable part and changed my_func according to the following:
template <typename T> void my_func() {
static T x;
}
int main() {
my_func<int>();
return 0;
}
Now this was interesting to me but the memory layout became:
.text: 1845
.data: 620
.bss: 4
Where did my static go? Whether I initialize it to any value static declared within templated functions doesn't seem to apprear nor in .DS neither in .BSS... Even if I instantiate another instance of that template function with different type for example my_func<float>() nothing is going to change. How is the compiler doing it? Where will it put those statics and how will these statics behave exactly the same as they weren't in templates - meaning they keep their values for each instantiated template function?
Probably the variable is being optimized away because it is not used. You may try to compile to assembly (gcc -S) and then lookup the variable in the output.
This experiment seems to confirm it:
> cat static.cpp
#include <iostream>
template<class T>
int func()
{
static int x = 0x666;
return 3;
}
int main()
{
std::cout << func<int>();
return 0;
}
> g++ -S static.cpp && c++filt < static.s | grep ::x
> sed -i 's/return 3/return x/' static.cpp
> g++ -S static.cpp && c++filt < static.s | grep ::x
movl int func<int>()::x(%rip), %eax
.weak int func<int>()::x
.section .data._ZZ4funcIiEivE1x,"awG",#progbits,int func<int>()::x,comdat
.type int func<int>()::x, #gnu_unique_object
.size int func<int>()::x, 4
int func<int>()::x:
I'm trying to move some code into a shared library (works fine when compiled stand-alone) but getting some issues with class inline functions. mingw/gcc v4.7.2.
Part of the problem appears to be because I prefer to define my inline functions outside the class declaration (it keeps the class declaration neater and easier to read). I always thought this was acceptable and equivalent to defining within the class declaration ... but that doesn't appear to always be the case. I've created a simple sample to demonstrate the problems. (Obviously the dllexport would normally be in a macro to switch between import/export.)
Header:
// Uncomment one at a time to see how it compiles with: -O2 -Winline
//#define INLINE_OPTION 1 // implicit - builds without inline warnings
#define INLINE_OPTION 2 // simple external inline - gives inline warnings
//#define INLINE_OPTION 3 // external forced inline - gives inline errors
class __attribute__((dllexport)) Dummy {
public:
Dummy() : m_int{0} {}
~Dummy() {}
#if INLINE_OPTION == 1
int get_int() const { return m_int; }
#else
int get_int() const;
#endif
int do_something();
private:
int m_int;
};
#if INLINE_OPTION == 2
inline int Dummy::get_int() const
{ return m_int; }
#endif
#if INLINE_OPTION == 3
inline __attribute__((always_inline)) int Dummy::get_int() const
{ return m_int; }
#endif
.cpp file:
int Dummy::do_something()
{
int i = get_int();
i *= 2;
return i;
}
As noted above, with INLINE_OPTION == 1 (implicit, in-class inline definition) the code compiles with out warning.
With INLINE_OPTION == 2 (out-of-class inline definition) I get this warning: int Dummy::get_int() const' can never be inlined because it uses attributes conflicting with inlining [-Winline]
With INLINE_OPTION == 3 (trying to force inline), I get the same warning as above, AND I get this error: error: inlining failed in call to always_inline 'int Dummy::get_int() const': function not inlinable, with the information about it being called from the first line inside Dummy::do_something() in the .cpp file. Notice this is about trying to inline the function within the library itself! For simple accessor functions this could be very a very significant overhead.
Am I doing something wrong? Is it gcc right in treating the out-of-class-definition inline function differently to in-class function definitions? (Am I really forced to clutter the class declaration?)
Note: The problem doesn't just effect things that I declare inline. It also effects anything declared as constexpr and even destructors declared as "= default" when inheritance is involved.
Edit:
Just tried with mingw64 / gcc v4.8.0 with the same results. Note that this includes the fact that option 1 does NOT inline in do_something (I checked the assembler output), so apparently the only difference between option 1 and option 2 is that only option 2 will gives the -Winline warning.
I don't know nothing about how to make shared libraries on Windows. In linux/OSX no special treatment is required in the source code, so that both shared (.so) and ordinary (.a) libraries can be made from the same sources without special treatment.
If you really do need a special attribute for symbols to be exported into shared libraries, then you may simply split the code, e.g.
namespace implementation_details {
class __attribute__((dllexport)) DummyBase
{
protected:
DummyBase() : m_int{0} {}
~DummyBase() {}
int do_something();
int m_int;
};
}
struct Dummy: private implementation_details::DummyBase
{
using implementation_details::DummyBase::do_something;
int get_int() const noexcept;
};
inline __attribute__((always_inline)) int Dummy::get_int() const noexcept
{ return m_int; }
Ok maybe my answer was a little cryptic... let me give you a quick example of what I mean using your code snippets.
dummy.h:
#ifndef _DUMMY_H_
#define _DUMMY_H_
class __attribute__((dllexport)) Dummy {
public:
Dummy() : m_int{0} {}
~Dummy() {}
int get_int() const;
int do_something();
private:
int m_int;
};
// here goes the include of the implementation header file
#include "dummy.h.impl"
#endif // _DUMMY_H_
dummy.h.impl:
// there will be no symbol for Dummy::get_int() in the dll.
// Only its contents are copied to the places where it
// is used. Placing this in the header gives other binaries
// you build with this lib the chance to do the same.
inline int Dummy::get_int() const
{ return m_int; }
Of course you could place the inline definitions just below your class declaration in the same header file. However, I find this still violates the separation of declaration and definition.
dummy.cpp:
// this method will become a symbol in the library because
// it is a C++ source file.
int Dummy::do_something()
{
// i would if i knew what to do...
return 0;
}
Hope I could be of help.
The edit I did on another post didn't seem to take, and anyway it seems some additional clarity may be appropriate, so I am posting details I've sent to another forum. In the code below class C is the work around to this problem - export only the non-inline members, not the whole class. As noted in the comments elsewhere, __declspec(dllexport) and __attribute__((dllexport)) are equivalent.
test.hpp
class __declspec(dllexport) A {
public:
int fa() { return m; }
int ga();
private:
int m{0};
};
class __declspec(dllexport) B {
public:
int fb();
int gb();
private:
int m{0};
};
inline int B::fb() { return m; }
class C {
public:
int fc() { return m; }
__declspec(dllexport) int gc();
private:
int m{0};
};
test.cpp
#include "test.hpp"
int A::ga() { return (fa() + 1); }
int B::gb() { return (fb() + 1); }
int C::gc() { return (fc() + 1); }
If you compile this with options: -std=c++11 -O2 -S -Winline (using mingw/ming64 with gcc v4.7.2 or v4.8.0) you can see the assembler produced for the library functions ga, gb and gc look like this:
ga:
subq $40, %rsp
.seh_stackalloc 40
.seh_endprologue
call _ZN1A2faEv
addl $1, %eax
addq $40, %rsp
ret
gb:
subq $40, %rsp
.seh_stackalloc 40
.seh_endprologue
call _ZN1B2fbEv
addl $1, %eax
addq $40, %rsp
ret
gc:
.seh_endprologue
movl (%rcx), %eax
addl $1, %eax
ret
and you get the warnings:
warning: function 'int B::fb()' can never be inlined because it uses attributes conflicting with inlining [-Winline]
warning: inlining failed in call to 'int B::fb()': function not inlinable [-Winline] (called from B::gb())
Notice that there were no warnings about fa not inlining (which is, I think, expected). But also notice that ga, gb and gc are all library functions. Whatever you may think about whether the inline functions themselves should be exported, there is no good reason why the inlines cannot be inlined inside the library. Hence I consider this a bug in the compiler.
Take a look around at well regarded code and see how much you find that exports only explicit members. For example those few parts of boost that get compiled into a library (eg: regex), use the class A technique, which means the many accessor functions are not being inlined inside the library.
But, all that aside, the answer for now is the class C technique (obviously in real code this has to be enclosed in a macro to switch between export and import as you would normally at the class level).
This is not a compiler bug, as some suggested. In C++ if function is inline, it has to be declared inline in every declaration. There are 5 properties that have to be met and one of them is:
An inline function with external linkage (e.g. not declared static) has the following additional properties:
1) It must be declared inline in every translation unit.
...
In your example, you first declared function Dummy::get_int() as non-inline inside class definition. It means that function cannot be redeclared as inline
Source: http://en.cppreference.com/w/cpp/language/inline
BTW: inline specifier works differently in C, where you can declare both inline and non-inline versions of the same function. Still, you have to implement both and ensure that they do the same thing.
Why don't you declare your function inline in class declaration (inline int get_int() const;)? Maybe error is there?
The compiler cannot inline a function which has to be exported in a dll. After all when called from executable linked with your dll the function should have an address. Most probably the call from do_something will be inlined but in the general case i think it's just impossible
I am trying to learn debugging using gdb. I have got the starting.
I just want to know is it possible to list all the functions of a class including the default one provided by the compiler?
Or even other way without using and IDE
Thanks
=============================================================================
The code I am trying:
#include <iostream>
class MyClass
{
public:
void Hello() {
}
int a;
};
int main(int argc, char **argv)
{
MyClass a;
MyClass b = a;
MyClass c;
c = a;
return 0;
}
=UPDATE 3====================================================================
I also want to list the compiler provided function name, if possible in gdb.
My question is in addition to question posted at
How to list class methods in gdb?
You have written too simple class. This advice:
Once you have the executable loaded in gdb, type break (or b) and hit the tab key.
is correct in general but in your case MinGW does not create anything for MyClass. I compiled your program with MinGW and disassembled it:
(gdb) disassemble /m main
Dump of assembler code for function main(int, char**):
13 {
0x0040138c <+0>: push %ebp
0x0040138d <+1>: mov %esp,%ebp
0x0040138f <+3>: and $0xfffffff0,%esp
0x00401392 <+6>: sub $0x10,%esp
0x00401395 <+9>: call 0x40193c <__main>
14 MyClass a;
15 MyClass b = a;
0x0040139a <+14>: mov 0xc(%esp),%eax
0x0040139e <+18>: mov %eax,0x8(%esp)
16 MyClass c;
17 c = a;
0x004013a2 <+22>: mov 0xc(%esp),%eax
0x004013a6 <+26>: mov %eax,0x4(%esp)
18 return 0;
0x004013aa <+30>: mov $0x0,%eax
19 }
0x004013af <+35>: leave
0x004013b0 <+36>: ret
End of assembler dump.
As you can see only move instructions. For example your assigments c = a; results in just two move instructions and no function calls:
0x004013a2 <+22>: mov 0xc(%esp),%eax
0x004013a6 <+26>: mov %eax,0x4(%esp)
As you can see the compiler chose not to generate anything for your class. In my opinion you chose too simple example to learn that you want.
I made you example a little bit more complex
#include <iostream>
class MyClass
{
public:
void Hello()
{
std::cout << "Hello\n";
}
int a;
};
int main(int argc, char **argv)
{
MyClass a;
a.Hello();
MyClass b = a;
MyClass c;
c = a;
return 0;
}
and under gdb break My shows this:
(gdb) b MyClass
MyClass MyClass::Hello()
(gdb) b MyClass
and this is the output of nm:
D:\src-c++\test.names>nm -C ./m.exe | grep MyClass
00404060 r .eh_frame$_ZN7MyClass5HelloEv
00401c20 t .text$_ZN7MyClass5HelloEv
00401c20 T MyClass::Hello()
I just wanted to see what are the default function generated by the class, if one does not write it
Change you member class variable from 'int a' to std::string a and you will see default functions generated by compiler
#include <iostream>
#include <string>
class MyClass
{
public:
void Hello() {
}
std::string a;
};
int main(int argc, char **argv)
{
MyClass a;
MyClass b = a;
MyClass c;
c = a;
return 0;
}
And these are the compile-generated functions:
>nm -C ./a.out | grep My
00000000004009b8 W MyClass::MyClass(MyClass const&)
0000000000400964 W MyClass::MyClass()
000000000040097c W MyClass::~MyClass()
0000000000400994 W MyClass::operator=(MyClass const&)
For example, when using break, type "break" space a single quote (') the name of your class, and hit TAB.
It'll list the candidates, including generated code.
I.e. break 'PotatoLaucher::<tab>
Once you have the executable loaded in gdb, type break (or b) and hit the tab key. This will give you a list of symbols that gdb can set a breakpoint at. Often times gdb will ask you if you really want to display all the possibilities (sometimes there are thousands of possibilities).
If you have some idea of what the function might be called, type the first few characters of the function name and hit tab. This will reduce the number of results to a manageable size.