1 /*
2  * Copyright (C) 2016 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 #ifndef LIBMEMUNREACHABLE_SCOPED_DISABLE_MALLOC_H_
18 #define LIBMEMUNREACHABLE_SCOPED_DISABLE_MALLOC_H_
19 
20 #include <memory>
21 
22 #include "android-base/macros.h"
23 
24 #include "ScopedAlarm.h"
25 #include "bionic.h"
26 #include "log.h"
27 
28 namespace android {
29 
30 class DisableMallocGuard {
31  public:
DisableMallocGuard()32   DisableMallocGuard() : disabled_(false) {}
~DisableMallocGuard()33   ~DisableMallocGuard() { Enable(); }
34 
Disable()35   void Disable() {
36     if (!disabled_) {
37       disabled_ = true;
38       malloc_disable();
39     }
40   }
41 
Enable()42   void Enable() {
43     if (disabled_) {
44       malloc_enable();
45       disabled_ = false;
46     }
47   }
48 
49  private:
50   DISALLOW_COPY_AND_ASSIGN(DisableMallocGuard);
51   bool disabled_;
52 };
53 
54 // Any calls to malloc or free from this thread will deadlock as long as this
55 // object is in scope.  Calls to malloc from other threads may succeed (for
56 // example if the allocation is satisfied out of the thread's tcache), or may
57 // block until the object is destroyed.
58 //
59 // Don't call fork() while malloc is disabled, it needs the same locks held
60 // here.
61 class ScopedDisableMalloc {
62  public:
ScopedDisableMalloc()63   ScopedDisableMalloc() { disable_malloc_.Disable(); }
64 
~ScopedDisableMalloc()65   ~ScopedDisableMalloc() { disable_malloc_.Enable(); }
66 
67  private:
68   DISALLOW_COPY_AND_ASSIGN(ScopedDisableMalloc);
69   DisableMallocGuard disable_malloc_;
70 };
71 
72 class ScopedDisableMallocTimeout {
73  public:
74   explicit ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::seconds(10))
timeout_(timeout)75       : timeout_(timeout), timed_out_(false), disable_malloc_() {
76     Disable();
77   }
78 
~ScopedDisableMallocTimeout()79   ~ScopedDisableMallocTimeout() { Enable(); }
80 
timed_out()81   bool timed_out() { return timed_out_; }
82 
Enable()83   void Enable() {
84     disable_malloc_.Enable();
85     alarm_ = nullptr;
86   }
87 
Disable()88   void Disable() {
89     // set up the alarm before disabling malloc so unique_ptr can be used
90     alarm_ = std::make_unique<ScopedAlarm>(timeout_, [&]() {
91       disable_malloc_.Enable();
92       timed_out_ = true;
93     });
94 
95     disable_malloc_.Disable();
96   }
97 
98  private:
99   DISALLOW_COPY_AND_ASSIGN(ScopedDisableMallocTimeout);
100   std::chrono::milliseconds timeout_;
101   bool timed_out_;
102   std::unique_ptr<ScopedAlarm> alarm_;
103   DisableMallocGuard disable_malloc_;
104 };
105 
106 }  // namespace android
107 
108 #endif  // LIBMEMUNREACHABLE_SCOPED_DISABLE_MALLOC_H_
109