Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Операционные системы > Linux (Ubuntu, Debian, Red Hat, CentOS, Mint)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.06.2014, 01:26   #1
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Здравствуйте.
Суть вопроса в том, как обезопасить обращения из конструктора/деструктора деструктора глобальных объектов к стандартным библиотекам Си/Си++.

Например, в windows msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx говорят о том, что во время выполнения кон/дес нет гарантий того, что стд библиотеки будут загружены.

Неужели нельзя сделать загрузку/выгрузку двухэтапной, сначала загружаем все библиотеки, а потом вызываем конструкторы.

В общем в Linuxe это проблема актуальна? Любые полезные ссылки приветствуются.

Понял как правильно:
Код:
Obj &get()
{
    static Ojb obj;
    return obj;
}
Вопросов больше не имею.

Такой способ поможет в нужное время вызвать конструктор, а с деструктормами проблема не решена. Без правильного порядка выгрузки вопрос не решить.

Видимо про беспорядочную загрузку/выгрузку - сказки от MS, во всяком случаи в Linux порядок имеется. Такой тест набросал (текущая директория /usr/local/lib):
Код:
// 1.cpp
#include <iostream>
struct S1 { S1() {std::cout << "1::constr\n";}  ~S1() {std::cout << "1::destr\n";} }s1;
// 2.cpp
#include <iostream>
struct S2 { S1() {std::cout << "2::constr\n";}  ~S1() {std::cout << "2::destr\n";} }s2;
// 3.cpp
#include <iostream>
struct S3 { S1() {std::cout << "3::constr\n";}  ~S1() {std::cout << "3::destr\n";} }s3;
// 4.cpp
#include <iostream>
struct S4 { S1() {std::cout << "4::constr\n";}  ~S1() {std::cout << "4::destr\n";} }s4;
// 5.cpp
#include <iostream>
struct S5 { S1() {std::cout << "5::constr\n";}  ~S1() {std::cout << "5::destr\n";} }s5;
// 6.cpp
#include <iostream>
struct S6 { S1() {std::cout << "6::constr\n";}  ~S1() {std::cout << "6::destr\n";} }s6;
// ex.cpp
#include <iostream>
int main() { std::cout << "ex::main\n"; return 0; }
Схема зависимостей между библиотеками (1 ни от кого не зависит):
.............................->4->5
1->2->3->
.............................->6
#g++ 1.cpp -o lib1.so -fpic -shared
#g++ lib1.so 2.cpp -o lib2.so -fpic -shared
#g++ lib2.so 3.cpp -o lib3.so -fpic -shared
#g++ lib3.so 4.cpp -o lib4.so -fpic -shared
#g++ lib4.so 5.cpp -o lib5.so -fpic -shared
#g++ lib3.so 6.cpp -o lib6.so -fpic -shared
#ldconfig
Линкуем все либы с исполняемым файлом:
#g++ lib3.so lib1.so lib6.so lib2.so lib5.so lib4.so ex.cpp -o ex
#./ex
1::constr
2::constr
3::constr
4::constr
5::constr
6::constr
ex::main
6:: destr
5:: destr
4:: destr
3:: destr
2:: destr
1:: destr

Во время экспериментов столкнулся со странностью, почему так получается?
Код:
// 1.cpp
#include <iostream>
struct S
{
    S() {std::cout << "1::constr\n";}
    ~S() {std::cout << "1::destr\n";}
}s;
// 2.cpp
#include <iostream>
struct S
{
    S() {std::cout << "2::constr\n";}
    ~S() {std::cout << "2::destr\n";}
}s;
// ex.cpp
#include <iostream>
int main()
{
    cout << "ex::main\n";
    return 0;
}
#g++ 1.cpp -fpic -shared -o lib1.so
#g++ 2.cpp -fpic -shared -o lib2.so
#g++ ex.cpp lib1.so lib2.so -o ex
#ldconfig
#./ex
1::constr
1::constr // Должно быть 2::constr ?
ex::main
1:: destr
1:: destr // Должно быть 2:: destr ?

Т.е. мы берем две готовы либы.so, линкуем с исполняемым файлом и как-будто одна либа загружается дважды. Мы ведь можем слинковать программу с сторонними библиотеками, никаких гарантий об уникальности имен быть не может, по-моему смахивает на ошибку.

Последний раз редактировалось Stilet; 19.06.2014 в 19:18.
220Volt вне форума Ответить с цитированием
Старый 18.06.2014, 10:04   #2
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Цитата:
Сообщение от 220Volt Посмотреть сообщение
Видимо про беспорядочную загрузку/выгрузку - сказки от MS, во всяком случаи в Linux порядок имеется.
Если бы вы потрудились попробовать тот же тест под виндой, у вас получулся бы точно такой же результат, но ведь конечно плевать на Microsoft круче.

Вы путаете порядок загрузки библиотек, что регламентировано, с порядком вызова конструкторов у глобальных объектов, что НЕ регламентировано. Если в каком-то компиляторе/платформе есть что-то, похожее на порядок, то это совпадение, на которое рассчитывать не стоит.

Сделайте ОДНУ библиоетку, с тремя файлами - a.c b.c и c.c
В каждой сделайте глобальный объект с конструктором.
Скомпилируйте программу несколько раз, меняя порядок файлов в командной строке.
Уверен, вас ждет много интересного.

Если будете использовать глобальные объекты, вам хотя бы будет гарантирован порядок удаления - он ВСЕГДА строго наоборот созданию.

Если будете использовать singleton, тогда либо надо самому создавать и удалять объекты и заботиться о том, чтоб это делалось в правильном порядке, либо порядок удаления объектов вам не гарантируется, если вообще они будут удаляться (если честно - не в курсе, не использую глобальные объекты, чего и вам желаю).

Можете сделать ОДИН глобальный объект, у кого будут переменные из нужных классов.
waleri на форуме Ответить с цитированием
Старый 18.06.2014, 10:57   #3
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Если бы вы потрудились попробовать тот же тест под виндой, у вас получулся бы точно такой же результат, но ведь конечно плевать на Microsoft круче.

Вы путаете порядок загрузки библиотек, что регламентировано, с порядком вызова конструкторов у глобальных объектов, что НЕ регламентировано. Если в каком-то компиляторе/платформе есть что-то, похожее на порядок, то это совпадение, на которое рассчитывать не стоит.

Сделайте ОДНУ библиоетку, с тремя файлами - a.c b.c и c.c
В каждой сделайте глобальный объект с конструктором.
Скомпилируйте программу несколько раз, меняя порядок файлов в командной строке.
Уверен, вас ждет много интересного.

Если будете использовать глобальные объекты, вам хотя бы будет гарантирован порядок удаления - он ВСЕГДА строго наоборот созданию.

Если будете использовать singleton, тогда либо надо самому создавать и удалять объекты и заботиться о том, чтоб это делалось в правильном порядке, либо порядок удаления объектов вам не гарантируется, если вообще они будут удаляться (если честно - не в курсе, не использую глобальные объекты, чего и вам желаю).

Можете сделать ОДИН глобальный объект, у кого будут переменные из нужных классов.
Валерий, я не понимаю зачем мне эксперементировать с cpp файлам, я в курсе что нельзя предвидеть в каком из cpp объект будет создан раньше. Что я напутал? Вы эти слова понимаете как-то по другому?
Код:
The entry-point function should perform only simple initialization or termination tasks. It must not call the 
LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency 
loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. 
Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary) during 
process termination, because this can result in a DLL being used after the system has executed its termination code.

Because Kernel32.dll is guaranteed to be loaded in the process address space when the entry-point function is called, 
calling functions in Kernel32.dll does not result in the DLL being used before its initialization code has been executed. 
Therefore, the entry-point function can call functions in Kernel32.dll that do not load other DLLs. For example, DllMain 
can create synchronization objects such as critical sections and mutexes, and use TLS. Unfortunately, there is not a 
comprehensive list of safe functions in Kernel32.dll.

Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For 
example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other 
system components. Conversely, calling functions such as these during termination can cause access violation errors 
because the corresponding component may already have been unloaded or uninitialized.

Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads 
or processes. Deadlocks may occur as a result.

For information on best practices when writing a DLL, 
see http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx.

If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors 
and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors 
and destructors and any code that is called from them.
Т.е. единственное что они гарантируют это наличие Kernel32.dll в адресном пространстве процесса. Более того, возможна выгрузка библиотек из пространства процесса до выгрузки использующей библиотеки.

Цитата:
Сообщение от 220Volt Посмотреть сообщение
Во время экспериментов столкнулся со странностью, почему так получается?
Код:
// 1.cpp
#include <iostream>
struct S
{
    S() {std::cout << "1::constr\n";}
    ~S() {std::cout << "1::destr\n";}
}s;
// 2.cpp
#include <iostream>
struct S
{
    S() {std::cout << "2::constr\n";}
    ~S() {std::cout << "2::destr\n";}
}s;
// ex.cpp
#include <iostream>
int main()
{
    cout << "ex::main\n";
    return 0;
}
#g++ 1.cpp -fpic -shared -o lib1.so
#g++ 2.cpp -fpic -shared -o lib2.so
#g++ ex.cpp lib1.so lib2.so -o ex
#ldconfig
#./ex
1::constr
1::constr // Должно быть 2::constr ?
ex::main
1:: destr
1:: destr // Должно быть 2:: destr ?

Т.е. мы берем две готовы либы.so, линкуем с исполняемым файлом и как-будто одна либа загружается дважды. Мы ведь можем слинковать программу с сторонними библиотеками, никаких гарантий об уникальности имен быть не может, по-моему смахивает на ошибку.
Ребят, что думаете по этому поводу? С моей стороны ошибок не видно? Я хочу начать жаловаться в различные заведения, неудобно будет если сам не прав.

Последний раз редактировалось Stilet; 19.06.2014 в 19:23.
220Volt вне форума Ответить с цитированием
Старый 18.06.2014, 14:05   #4
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

в анонимные неймспейсы помести свои структуры
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance
pproger вне форума Ответить с цитированием
Старый 18.06.2014, 14:14   #5
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от pproger Посмотреть сообщение
в анонимные неймспейсы помести свои структуры
Не понял, пример если можно.

Еще так пробывал:
Код:

// 1.cpp
#include <iostream>
struct S
{
    int val;
    S() {val =1; std::cout << "1::constr\n";}
    ~S() {std::cout << "1::destr\n";}
}s;
extern int f1() {return s.val;}
// 2.cpp
#include <iostream>
struct S
{
    int val;
    S() {int val=2; std::cout << "2::constr\n";}
    ~S() {std::cout << "2::destr\n";}
}s;
extern int f2() {return s.val;}
// ex.cpp
#include <iostream>
extern int f1();
extern int f2();
int main()
{
    std::cout << "ex::main\n";
    std::cout <<"f1 = "<< f1() << "\n";
    std::cout <<"f2 = "<< f2() << "\n";
    return 0;
}
1::constr
1::constr
ex::main
f1 = 1
f2 = 1
1:: destr
1:: destr

Пожаловался: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61549

Последний раз редактировалось Stilet; 19.06.2014 в 19:24.
220Volt вне форума Ответить с цитированием
Старый 18.06.2014, 18:35   #6
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Вы бы язык сначала выучили, прежде чем жаловаться.
waleri на форуме Ответить с цитированием
Старый 19.06.2014, 04:51   #7
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Всё waleri, черная метка.

Один вопрос: как в анонимном namespace сделать обыкновенный static член? Т.е. который будет одним для всех экземляров?
Код:
// header.h
namespace{
    struct S{
        static int data;   // что и где прописать чтобы все экземпляры ссылались в одно место?
    };
}
Получается что при подключении какой-то либы, я должен задумываться как она там написана, чтобы случайно не изменить ее поведение. Жесть ...

Последний раз редактировалось Stilet; 19.06.2014 в 19:25.
220Volt вне форума Ответить с цитированием
Старый 19.06.2014, 18:47   #8
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

>Один вопрос: как в анонимном namespace сделать обыкновенный static член? Т.е. который будет одним для всех экземляров?

так же, как и в обычном, не анонимном
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance
pproger вне форума Ответить с цитированием
Старый 19.06.2014, 19:05   #9
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Наверное не уточнил: все экземпляры из разных .срр ссылались на одни данные. Т.е. анонимный namespace только для заглушки экспорта из библиотеки. Как обычно пытался, но чего-то не вышло.
220Volt вне форума Ответить с цитированием
Старый 19.06.2014, 20:13   #10
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

В целом вроде все ясно. Просто неявное связывание сильно различается у windows и linux. Первое знакомство было с win библиотеками. Мало того что в linux явно об экспорте не надо просить компилятор, так еще и предоставлен механизм подобный виртуальным функциям (догадваюсь об этом). Надо быть внимательным и не забывать про namespace'ы.

Всем спасибо.
220Volt вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как подружить std::map и глобальные объекты _Bers Общие вопросы C/C++ 18 28.06.2012 22:52
Динамические объекты 095 Общие вопросы Delphi 2 04.06.2011 19:09
объекты класса и динамические массивы alex_alpha Общие вопросы C/C++ 14 11.06.2010 01:32
Динамические объекты 095 Общие вопросы Delphi 1 04.10.2007 21:16