Search code examples
androidc++android-ndkstatic-initialization

Static variable getting pre initialized with random values


Can someone please explain why a member variable (char m_DBFileName[257]) of static variable (g_JournalDB) getting initialized with a random value? I expect it to be populated with '\0's.

enter image description here

More info: g_JournalDB is part of a dynamic library loaded on app startup via

public class MyApplication extends Application {
    static {
        System.loadLibrary("mylibrary");
        ...
        System.loadLibrary("mylibraryN");
    }
    @override
    public void onCreate() {...}
    ...
}

The screenshot above was taken from a breakpoint in onCreate() of MyApplication where g_JournalDB gets created. I can provide more info if needed.

EDIT: Is it possible that, since I am loading multiple .so files, one ore more .so files have overlapping memory map?

EDIT2: In the class constructor of cAMPDatabase, I am doing memset(m_DBFileName, 0, sizeof(m_DBFileName)) so I really expect that it is populated with '\0's.

UPDATE1: Later on in the app, I tried to update the g_JournalDB.m_DBFileName, I found out that I can no longer access the first 20 indexes. When I did a strncpy(m_DBFileName, "/data", 256);, the new value started in index 20. As you can see below, my string "/data" starts at index 20.

enter image description here

UPDATE2: I was able to determine that the issue is caused by error in memory:

09-07 07:57:11.417 309-309/? I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-07 07:57:11.417 309-309/? I/DEBUG: Build fingerprint: 'qcom/msm7808/msm7808:5.1.1/WMY57L/ittech01220402:userdebug/release-keys'
09-07 07:57:11.417 309-309/? I/DEBUG: Revision: '0'
09-07 07:57:11.417 309-309/? I/DEBUG: ABI: 'arm'
09-07 07:57:11.417 309-309/? I/DEBUG: pid: 22437, tid: 22437, name: zapplication.zapp  >>> com.zapplication.zapp <<<
09-07 07:57:11.418 309-309/? I/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x69e793d8
09-07 07:57:11.433 309-309/? I/DEBUG:     r0 0056a27c  r1 69e371ac  r2 0004222c  r3 a0bcab7c
09-07 07:57:11.433 309-309/? I/DEBUG:     r4 ffffffff  r5 a0e29428  r6 be876678  r7 be876618
09-07 07:57:11.433 309-309/? I/DEBUG:     r8 be897ab0  r9 b7a7f1c8  sl be897a40  fp b7a7f1c8
09-07 07:57:11.434 309-309/? I/DEBUG:     ip a09df2f8  sp be876600  lr a094afa9  pc a094afd8  cpsr 300f0030
09-07 07:57:11.434 309-309/? I/DEBUG: backtrace:
09-07 07:57:11.434 309-309/? I/DEBUG:     #00 pc 0001bfd8  /data/app/com.zapplication.zapp-1/lib/arm/libmylibrary.so (_ZN12cAMPDatabase11CreateTableEPKcP18DB_DATA_DEFINITION+79)

UPDATE3: For those who asked, here is the cAMPDatabase class constructor:

cAMPDatabase::cAMPDatabase() {
    m_DBHandle = NULL;
    memset(m_DBFileName, 0, sizeof(m_DBFileName));
    memset(m_Tables, 0, sizeof(m_Tables));
    m_TblCount=0;
    this->m_SqlObj = this->NewStmt();
}

Here is the header definition (full definition here) for the class:

class cAMPDatabase {    
    friend class cAMPSqlStmt;
public:
    cAMPDatabase();
    virtual ~cAMPDatabase();
    // the rest of public variables and functions here ...
protected:  
    char m_DBFileName[257];
    // the rest of protected variables and functions here ...
}

Solution

  • You have a massive class and I recommend that you initialize all member variables in the one contructor you have.

    Example:

    cAMPDatabase::cAMPDatabase() :
        m_DBHandle{nullptr},
        m_SqlObj{nullptr},    // see note
        m_ErrorCode{0},
        m_DBFileName{},
        m_TableName{},
        m_TableFldDef{},
        m_Tables{},
        m_TblCount{}
    {
        m_SqlObj = NewStmt();
    }
    

    Note: The pointer m_SqlObj is created by calling the non-static member function NewStmt(). For that to make sense, the cAMPDatabase instance would have to carry some information but there is nothing in the code that puts anything in the member variables before calling NewStmt() - except the this pointer.

    I therefore assume that the definition of NewStmt() looks roughly like this:

    cAMPSqlStmt* cAMPDatabase::NewStmt(void) {
        return new cAMPSqlStmt(this);
    }
    

    Unless cAMPSqlStmt requires cAMPDatabase to be fully initialized, the initialization of cAMPDatabase could then be made like this:

    cAMPDatabase::cAMPDatabase() :
        m_DBHandle{nullptr},
        m_SqlObj{NewStmt()}, // or m_SqlObj{new cAMPSqlStmt(this)}
        m_ErrorCode{0},
        m_DBFileName{},
        m_TableName{},
        m_TableFldDef{},
        m_Tables{},
        m_TblCount{}
    {}