1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include <dlfcn.h>
20 #include <libgen.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 
25 #include <string>
26 
TEST(atexit,sofile)27 TEST(atexit, sofile) {
28   std::string atexit_call_sequence;
29   bool valid_this_in_static_dtor = false;
30   bool attr_dtor_called = false;
31 
32   void* handle = dlopen("libtest_atexit.so", RTLD_NOW);
33   ASSERT_TRUE(handle != nullptr);
34 
35   typedef int (*int_fn)(void);
36   int_fn get_cxx_ctor_called, get_attr_ctor_called;
37   get_cxx_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_cxx_ctor_called"));
38   get_attr_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_attr_ctor_called"));
39   ASSERT_TRUE(get_cxx_ctor_called != nullptr);
40   ASSERT_TRUE(get_attr_ctor_called != nullptr);
41 
42   ASSERT_EQ(1, get_cxx_ctor_called());
43   ASSERT_EQ(1, get_attr_ctor_called());
44 
45   void* sym = dlsym(handle, "register_atexit");
46   ASSERT_TRUE(sym != nullptr);
47   reinterpret_cast<void (*)(std::string*, bool*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor, &attr_dtor_called);
48 
49   ASSERT_EQ(0, dlclose(handle));
50   // this test verifies atexit call from atexit handler. as well as the order of calls
51   ASSERT_EQ("Humpty Dumpty sat on a wall", atexit_call_sequence);
52   ASSERT_TRUE(valid_this_in_static_dtor);
53   ASSERT_TRUE(attr_dtor_called);
54 }
55 
56 class TestMainStaticDtorClass {
57  public:
TestMainStaticDtorClass()58   TestMainStaticDtorClass() {
59     expected_this = this;
60   }
61 
~TestMainStaticDtorClass()62   ~TestMainStaticDtorClass() {
63     if (this != expected_this) {
64       fprintf(stderr, "\nerror: static d-tor called with incorrect this pointer: %p, expected: %p\n", this, expected_this);
65     } else {
66       fprintf(stderr, "6");
67     }
68   }
69  private:
70   static const TestMainStaticDtorClass* expected_this;
71 };
72 
73 const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = nullptr;
74 
atexit_func5()75 static void atexit_func5() {
76   fprintf(stderr, "5");
77 }
78 
atexit_func4()79 static void atexit_func4() {
80   fprintf(stderr, "4");
81 }
82 
atexit_func3()83 static void atexit_func3() {
84   fprintf(stderr, "3");
85   atexit(atexit_func4);
86 }
87 
atexit_func2()88 static void atexit_func2() {
89   fprintf(stderr, "2");
90 }
91 
atexit_func1()92 static void atexit_func1() {
93   fprintf(stderr, "1");
94 }
95 
atexit_main()96 static void atexit_main() {
97   // This should result in "123456" output to stderr
98   static TestMainStaticDtorClass static_obj;
99   atexit(atexit_func5);
100   atexit(atexit_func3);
101   atexit(atexit_func2);
102   atexit(atexit_func1);
103   exit(0);
104 }
105 
TEST(atexit,exit)106 TEST(atexit, exit) {
107   ASSERT_EXIT(atexit_main(), testing::ExitedWithCode(0), "123456");
108 }
109 
110