Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f502182a authored by Hans Boehm's avatar Hans Boehm Committed by Gerrit Code Review
Browse files

Merge "Prepare to fail in RefBase destructor if count is untouched"

parents c7815d67 9d3146af
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@

#include <deque>
#include <iterator>
#include <memory>
#include <string>
#include <vector>

+25 −4
Original line number Diff line number Diff line
@@ -16,16 +16,15 @@

#define LOG_TAG "CallStack"

#include <utils/CallStack.h>

#include <memory>

#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>

#include <backtrace/Backtrace.h>

#define CALLSTACK_WEAK  // Don't generate weak definitions.
#include <utils/CallStack.h>

namespace android {

CallStack::CallStack() {
@@ -76,4 +75,26 @@ void CallStack::print(Printer& printer) const {
    }
}

// The following four functions may be used via weak symbol references from libutils.
// Clients assume that if any of these symbols are available, then deleteStack() is.

CallStack::CallStackUPtr CallStack::getCurrentInternal(int ignoreDepth) {
    CallStack::CallStackUPtr stack(new CallStack());
    stack->update(ignoreDepth + 1);
    return stack;
}

void CallStack::logStackInternal(const char* logtag, const CallStack* stack,
                                 android_LogPriority priority) {
    stack->log(logtag, priority);
}

String8 CallStack::stackToStringInternal(const char* prefix, const CallStack* stack) {
    return stack->toString(prefix);
}

void CallStack::deleteStack(CallStack* stack) {
    delete stack;
}

}; // namespace android
+34 −23
Original line number Diff line number Diff line
@@ -17,17 +17,23 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0

#include <memory>

#include <utils/RefBase.h>

#include <utils/CallStack.h>

#include <utils/Mutex.h>

#ifndef __unused
#define __unused __attribute__((__unused__))
#endif

// compile with refcounting debugging enabled
// Compile with refcounting debugging enabled.
#define DEBUG_REFS 0

// The following three are ignored unless DEBUG_REFS is set.

// whether ref-tracking is enabled by default, if not, trackMe(true, false)
// needs to be called explicitly
#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
@@ -42,6 +48,11 @@
// log all reference counting operations
#define PRINT_REFS 0

// Continue after logging a stack trace if ~RefBase discovers that reference
// count has never been incremented. Normally we conspicuously crash in that
// case.
#define DEBUG_REFBASE_DESTRUCTION 1

// ---------------------------------------------------------------------------

namespace android {
@@ -184,7 +195,7 @@ public:
                char inc = refs->ref >= 0 ? '+' : '-';
                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
                refs->stack.log(LOG_TAG);
                CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
                refs = refs->next;
            }
@@ -198,14 +209,14 @@ public:
                char inc = refs->ref >= 0 ? '+' : '-';
                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
                refs->stack.log(LOG_TAG);
                CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
                refs = refs->next;
            }
        }
        if (dumpStack) {
            ALOGE("above errors at:");
            CallStack stack(LOG_TAG);
            CallStack::logStack(LOG_TAG);
        }
    }

@@ -279,7 +290,7 @@ public:
                     this);
            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
            if (rc >= 0) {
                write(rc, text.string(), text.length());
                (void)write(rc, text.string(), text.length());
                close(rc);
                ALOGD("STACK TRACE for %p saved in %s", this, name);
            }
@@ -294,7 +305,7 @@ private:
        ref_entry* next;
        const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
        CallStack stack;
        CallStack::CallStackUPtr stack;
#endif
        int32_t ref;
    };
@@ -311,7 +322,7 @@ private:
            ref->ref = mRef;
            ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
            ref->stack.update(2);
            ref->stack = CallStack::getCurrent(2);
#endif
            ref->next = *refs;
            *refs = ref;
@@ -346,7 +357,7 @@ private:
                ref = ref->next;
            }

            CallStack stack(LOG_TAG);
            CallStack::logStack(LOG_TAG);
        }
    }

@@ -373,7 +384,7 @@ private:
                     inc, refs->id, refs->ref);
            out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
            out->append(refs->stack.toString("\t\t"));
            out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
            out->append("\t\t(call stacks disabled)");
#endif
@@ -700,16 +711,16 @@ RefBase::~RefBase()
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
        // We never acquired a strong reference on this object.
        LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
                "RefBase: Explicit destruction with non-zero weak "
                "reference count");
        // TODO: Always report if we get here. Currently MediaMetadataRetriever
        // C++ objects are inconsistently managed and sometimes get here.
        // There may be other cases, but we believe they should all be fixed.
        delete mRefs;
#if DEBUG_REFBASE_DESTRUCTION
        // Treating this as fatal is prone to causing boot loops. For debugging, it's
        // better to treat as non-fatal.
        ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
        CallStack::logStack(LOG_TAG);
#else
        LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
#endif
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
    const_cast<weakref_impl*&>(mRefs) = nullptr;
+61 −3
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H

#include <memory>

#include <android/log.h>
#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
@@ -25,6 +27,11 @@
#include <stdint.h>
#include <sys/types.h>

#ifndef CALLSTACK_WEAK
#define CALLSTACK_WEAK __attribute__((weak))
#endif
#define ALWAYS_INLINE __attribute__((always_inline))

namespace android {

class Printer;
@@ -63,7 +70,58 @@ public:
    // Get the count of stack frames that are in this call stack.
    size_t size() const { return mFrameLines.size(); }

    // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
    // to disappear again shortly, once a better replacement facility exists.
    // The replacement facility will be incompatible!

    // Debugging accesses to some basic functionality. These use weak symbols to
    // avoid introducing a dependency on libutilscallstack. Such a dependency from
    // libutils results in a cyclic build dependency. These routines can be called
    // from within libutils. But if the actual library is unavailable, they do
    // nothing.
    //
    // DO NOT USE THESE. They will disappear.
    struct StackDeleter {
        void operator()(CallStack* stack) { deleteStack(stack); }
    };

    typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;

    // Return current call stack if possible, nullptr otherwise.
    static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
        if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
            ALOGW("CallStack::getCurrentInternal not linked, returning null");
            return CallStackUPtr(nullptr);
        } else {
            return getCurrentInternal(ignoreDepth);
        }
    }
    static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
                                       android_LogPriority priority = ANDROID_LOG_DEBUG) {
        if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
            logStackInternal(logtag, stack, priority);
        } else {
            ALOGW("CallStack::logStackInternal not linked");
        }
    }
    static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
                                               const CallStack* stack = getCurrent().get()) {
        if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
            return stackToStringInternal(prefix, stack);
        } else {
            return String8("<CallStack package not linked>");
        }
    }

  private:
    static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
    static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
                                                android_LogPriority priority);
    static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
    // The deleter is only invoked on non-null pointers. Hence it will never be
    // invoked if CallStack is not linked.
    static void CALLSTACK_WEAK deleteStack(CallStack* stack);

    Vector<String8> mFrameLines;
};