静态变量使用随机值进行预初始化
Static variable getting pre initialized with random values
谁能解释一下为什么静态变量 (g_JournalDB) 的成员变量 (char m_DBFileName[257]
) 会被初始化为一个随机值?我希望它填充 '\0's.
更多信息:g_JournalDB 是通过
在应用程序启动时加载的动态库的一部分
public class MyApplication extends Application {
static {
System.loadLibrary("mylibrary");
...
System.loadLibrary("mylibraryN");
}
@override
public void onCreate() {...}
...
}
上面的屏幕截图是从创建 g_JournalDB 的 MyApplication 的 onCreate() 中的断点截取的。如果需要,我可以提供更多信息。
编辑:是否有可能,因为我正在加载多个 .so 文件,一个或多个 .so 文件有重叠的内存映射?
EDIT2:在 cAMPDatabase 的 class 构造函数中,我正在做 memset(m_DBFileName, 0, sizeof(m_DBFileName))
所以我真的希望它填充了 '\0's。
UPDATE1:稍后在应用程序中,我尝试更新 g_JournalDB.m_DBFileName
,我发现我无法再访问前 20 个索引。当我执行 strncpy(m_DBFileName, "/data", 256);
时,新值从索引 20 开始。如下所示,我的字符串“/data”从索引 20 开始。
更新 2:我能够确定问题是由内存错误引起的:
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)
更新 3:对于那些提问的人,这里是 cAMPDatabase class 构造函数:
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();
}
这是 class 的 header 定义(完整定义 here):
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 ...
}
你试过 m_DBFileName
作为 std::string
而不是 char *
或 array
吗?
并且请尝试共享一个minimal reproducible example用于静态变量初始化。
很高兴知道您能够找到最终成为最可能情况的内存错误。
尽管 std::string
class 在大多数情况下是首选,因为它是 标准并且更便于处理 .
另外,如果这个问题持续存在(非标准编译器?),其他可能的解决方法可能是通过 memset(&m_DBFileName[0], 0, sizeof(m_DBFileName))
和 strncpy
显式选择指向第 0 个索引的指针,而不是简单的数组name m_DBFileName
因为它不是指向第一个元素的指针,而是衰减到第一个元素。
你有一个巨大的class,我建议你在你拥有的一个构造函数中初始化所有成员变量。
示例:
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();
}
注:指针m_SqlObj
是调用非static
成员函数NewStmt()
创建的。为了使它有意义,cAMPDatabase
实例必须携带一些信息,但在调用 NewStmt()
之前,代码中没有任何内容将任何内容放入成员变量中——除了 this
指针。
因此我假设 NewStmt()
的定义大致如下所示:
cAMPSqlStmt* cAMPDatabase::NewStmt(void) {
return new cAMPSqlStmt(this);
}
除非cAMPSqlStmt
要求cAMPDatabase
完全初始化,cAMPDatabase
的初始化可以这样进行:
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{}
{}
我认为有两种可能的解决方案:
- 使用
std::string
-- 原因显而易见,但您可能没有那种自由
- 初始化 char 数组,而不是在构造函数中更改它。
有区别
static char m_DBFileName[257];
(仅声明,值冻结)
static char m_DBFileName[257] = {0,0,...0};
(如果必须的话,但这是声明+初始化)
如果不想使用最后一个选项,也可以
class cAMPDatabase {
static char m_DBFileName[257];
public:
cAMPDatabase(): m_DBFileName({0,0,...0}) {};
};
如果你真的需要初始化在不同的编译单元中是相同的(不确定你的多个 DLL 是如何进行的)那么你可能想使用 static inline
而不是静态的,或者更优雅地, constexpr
。请参阅 和下面的文字。
谁能解释一下为什么静态变量 (g_JournalDB) 的成员变量 (char m_DBFileName[257]
) 会被初始化为一个随机值?我希望它填充 '\0's.
更多信息:g_JournalDB 是通过
在应用程序启动时加载的动态库的一部分public class MyApplication extends Application {
static {
System.loadLibrary("mylibrary");
...
System.loadLibrary("mylibraryN");
}
@override
public void onCreate() {...}
...
}
上面的屏幕截图是从创建 g_JournalDB 的 MyApplication 的 onCreate() 中的断点截取的。如果需要,我可以提供更多信息。
编辑:是否有可能,因为我正在加载多个 .so 文件,一个或多个 .so 文件有重叠的内存映射?
EDIT2:在 cAMPDatabase 的 class 构造函数中,我正在做 memset(m_DBFileName, 0, sizeof(m_DBFileName))
所以我真的希望它填充了 '\0's。
UPDATE1:稍后在应用程序中,我尝试更新 g_JournalDB.m_DBFileName
,我发现我无法再访问前 20 个索引。当我执行 strncpy(m_DBFileName, "/data", 256);
时,新值从索引 20 开始。如下所示,我的字符串“/data”从索引 20 开始。
更新 2:我能够确定问题是由内存错误引起的:
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)
更新 3:对于那些提问的人,这里是 cAMPDatabase class 构造函数:
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();
}
这是 class 的 header 定义(完整定义 here):
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 ...
}
你试过 m_DBFileName
作为 std::string
而不是 char *
或 array
吗?
并且请尝试共享一个minimal reproducible example用于静态变量初始化。
很高兴知道您能够找到最终成为最可能情况的内存错误。
尽管 std::string
class 在大多数情况下是首选,因为它是 标准并且更便于处理 .
另外,如果这个问题持续存在(非标准编译器?),其他可能的解决方法可能是通过 memset(&m_DBFileName[0], 0, sizeof(m_DBFileName))
和 strncpy
显式选择指向第 0 个索引的指针,而不是简单的数组name m_DBFileName
因为它不是指向第一个元素的指针,而是衰减到第一个元素。
你有一个巨大的class,我建议你在你拥有的一个构造函数中初始化所有成员变量。
示例:
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();
}
注:指针m_SqlObj
是调用非static
成员函数NewStmt()
创建的。为了使它有意义,cAMPDatabase
实例必须携带一些信息,但在调用 NewStmt()
之前,代码中没有任何内容将任何内容放入成员变量中——除了 this
指针。
因此我假设 NewStmt()
的定义大致如下所示:
cAMPSqlStmt* cAMPDatabase::NewStmt(void) {
return new cAMPSqlStmt(this);
}
除非cAMPSqlStmt
要求cAMPDatabase
完全初始化,cAMPDatabase
的初始化可以这样进行:
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{}
{}
我认为有两种可能的解决方案:
- 使用
std::string
-- 原因显而易见,但您可能没有那种自由 - 初始化 char 数组,而不是在构造函数中更改它。
有区别
static char m_DBFileName[257];
(仅声明,值冻结)static char m_DBFileName[257] = {0,0,...0};
(如果必须的话,但这是声明+初始化)
如果不想使用最后一个选项,也可以
class cAMPDatabase {
static char m_DBFileName[257];
public:
cAMPDatabase(): m_DBFileName({0,0,...0}) {};
};
如果你真的需要初始化在不同的编译单元中是相同的(不确定你的多个 DLL 是如何进行的)那么你可能想使用 static inline
而不是静态的,或者更优雅地, constexpr
。请参阅