シグナル 11 (SIGSEGV)、コード 2 (SEGV_ACCERR) の原因と解決方法

暗号文は簡単ではありません。転載する場合は出典を示して
ください


1 結論

残業している深夜にこの記事を開いたのかもしれませんが、本当に時間がなくて本当に家に帰りたいので、ナンセンスなことから始めることはできません。今回は参考までに先に結論を出しましょう、駄目なら急いで他を探しましょう…

SIGSEGVはい、表示されます进程执行了一个无效的内存引用現在、ここにリストされているさまざまな理由で 2 つのクラッシュが発生しています。

理由:

  1. 对象在使用时已被释放。
  2. 对象没有初始化。

もう少し拡張するには:

  1. 对象A用局部变量初始化,分配在栈上,函数结束就提前释放了。赋值给其他对象B,B在其他函数引用A时,出现崩溃。
  2. 对象没有被初始化,判空又不为空,使用时崩溃。

解決:

  1. 使用智能指针,或者A改成全局变量。
  2. 保证变量在使用前初始化,例如在构造函数初始化。

よし、次は詳しく話そう。

2 ケース 1 つのオブジェクトが使用中に解放された

2.1 問題の背景

Android C++ コードを記述した後、実行時にクラッシュし、ログは次のようになります。

11-25 15:07:25.546 24467 24527 E glesdemo: ReadMissingBones, m_BoneInfoMap address 0x7e70ed0f88, size 52


11-25 15:07:25.554 24467 24527 E glesdemo: GetBoneIDMap, m_BoneInfoMap size 0


11-25 15:07:25.654 24718 24718 I crash_dump64: performing dump of process 24467 (target tid = 24527)
11-25 15:07:25.655 24718 24718 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-25 15:07:25.655 24718 24718 F DEBUG   : Build fingerprint: 'Xiaomi/sagit/sagit:8.0.0/OPR1.170623.027/V10.2.1.0.OCACNFK:user/release-keys'
11-25 15:07:25.655 24718 24718 F DEBUG   : Revision: '0'
11-25 15:07:25.655 24718 24718 F DEBUG   : ABI: 'arm64'
11-25 15:07:25.655 24718 24718 F DEBUG   : pid: 24467, tid: 24527, name: GLThread 6769  >>> com.chenxf.opengles <<<
11-25 15:07:25.655 24718 24718 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x23d70a00000020
11-25 15:07:25.655 24718 24718 F DEBUG   :     x0   3c23d70a00000020  x1   0000007e70ed0ce0  x2   0000000000000018  x3   3c23d70a00000020
11-25 15:07:25.655 24718 24718 F DEBUG   :     x4   0000007e72355438  x5   0000007e70ed0f68  x6   0000007e70ed11a0  x7   0000000000000000
11-25 15:07:25.655 24718 24718 F DEBUG   :     x8   0000007e72355420  x9   3c23d70a00000020  x10  0000007e70ed0e98  x11  0000007e70ed11a0
11-25 15:07:25.655 24718 24718 F DEBUG   :     x12  0000007e71a44808  x13  0000000000000001  x14  ffffffffffffffff  x15  26204f3d44495400
11-25 15:07:25.656 24718 24718 F DEBUG   :     x16  0000007e72bbbac0  x17  0000007e72b828bc  x18  0000000000000001  x19  0000007e7efa5400
11-25 15:07:25.656 24718 24718 F DEBUG   :     x20  0000007e72b70ee4  x21  000000001384f730  x22  000000001384b8f0  x23  0000007e8f90ab47
11-25 15:07:25.656 24718 24718 F DEBUG   :     x24  0000000000000008  x25  0000007e7efa5498  x26  0000000000000000  x27  0000000000000000
11-25 15:07:25.656 24718 24718 F DEBUG   :     x28  0000000000000002  x29  0000007e70ed0c80  x30  0000007e72b79bfc
11-25 15:07:25.656 24718 24718 F DEBUG   :     sp   0000007e70ed0c70  pc   0000007e72b79bfc  pstate 0000000020000000
11-25 15:07:25.661 24718 24718 F DEBUG   :
11-25 15:07:25.661 24718 24718 F DEBUG   : backtrace:
11-25 15:07:25.661 24718 24718 F DEBUG   :     #00 pc 0000000000028bfc  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG   :     #01 pc 0000000000031780  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG   :     #02 pc 000000000003e1ec  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG   :     #03 pc 000000000003e1b8  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG   :     #04 pc 000000000003e16c  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG   :     #05 pc 000000000003e110  /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)

そのためのスタック情報はまったくありません。まったく何の線か分からないのですが、これは何が原因でしょうか?

最初に依存コードを次のようにリストします。
最初のクラスのアニメーター:

class Animator
{
    
    
public:
	Animator(Animation* animation)
	{
    
    
		m_CurrentAnimation = animation;
	}

	void CalculateBoneTransform()
	{
    
    
		//省略代码...
		std::map<std::string,BoneInfo> boneInfoMap = m_CurrentAnimation->GetBoneIDMap();
		DEBUG_LOGCATE();

		if (boneInfoMap.find(nodeName) != boneInfoMap.end())
		{
    
    
			DEBUG_LOGCATE();
			//省略代码...
		}
	}

private:
	Animation* m_CurrentAnimation;

};

2級アニメーション

class Animation
{
    
    
public:
	Animation() = default;

	Animation(const std::string& animationPath, ModelAnim* model)
	{
    
    
		m_BoneInfoMap = model.GetBoneInfoMap();//getting m_BoneInfoMap from Model class
		LOGCATE("ReadMissingBones, m_BoneInfoMap address %p, size %d", &m_BoneInfoMap,m_BoneInfoMap.size());
	}

	~Animation()
	{
    
    
	}

	inline const std::map<std::string,BoneInfo>& GetBoneIDMap() 
	{
    
    
		LOGCATE("GetBoneIDMap, m_BoneInfoMap size %d", m_BoneInfoMap.size());
		return m_BoneInfoMap;
	}

private:
	std::map<std::string, BoneInfo> m_BoneInfoMap;
};

3 番目のクラスは、上記の 2 つのクラスを初期化し、以下を使用します。

void Model3DAnimSample::Init() {
    
    
	Animation animation(path + "/model/vampire/dancing_vampire.dae", m_pModel);
    m_pAnimator = new Animator(&animation);
    //...
}

void Model3DAnimSample::Draw(int screenW, int screenH) {
    
    
	m_pAnimator->CalculateBoneTransform();
	//省略...
}

2.2 原因分析

ローカルで再現できるので、追跡するために多くのログを追加しました。上部のログの最初の 2 行を参照してください。

11-25 15:07:25.546 24467 24527 E glesdemo: ReadMissingBones, m_BoneInfoMap address 0x7e70ed0f88, size 52
11-25 15:07:25.554 24467 24527 E glesdemo: GetBoneIDMap, m_BoneInfoMap size 0

この m_BoneInfoMap は、値を代入すると 52 になりますが、Animator の CalculateBoneTransform 関数で呼び出すと、値を読み取って 0 になり、それ以上使用するとクラッシュします。

なぜ?長い間読んだ後、m_BoneInfoMap はどこも変更されていません! ! !

スタック情報をもう一度見てみましょう。
11-25 15:07:25.655 24718 24718 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x23d70a00000020

この2文字の意味は?
SIGSEGV: プロセスが無効なメモリ参照を実行しました。
SEGV_MAPERR: スタック マップ エラーを示します。

それで、理由が出てきました:
在Init函数,animation是局部变量,栈上分配的,再赋值给m_pAnimator。 Init函数结束后,animation就无效了,后面m_pAnimator再使用animation,就是栈上的脏数据,所以出现了SIGSEGV

2.3 ソリューション

  1. Animation をクラスのグローバル変数にします。たった今
 	m_pAnimation = new Animation(path + "/model/vampire/dancing_vampire.dae", m_pModel);
    m_pAnimator = new Animator(m_pAnimation);
  1. スマート ポインターを使用して、アニメーション、つまり share_ptr を作成します。スマート ポインターについては、https://blog.csdn.net/newchenxf/article/details/116019535 を参照してください。

3 ケース 2 オブジェクトが初期化されていない

3.1 問題の背景

ケース 1 と同じスタック

12-27 16:06:13.513 20962 20962 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
12-27 16:06:13.513 20962 20962 F DEBUG   : Build fingerprint: 'Xiaomi/sagit/sagit:8.0.0/OPR1.170623.027/V10.2.1.0.OCACNFK:user/release-keys'
12-27 16:06:13.513 20962 20962 F DEBUG   : Revision: '0'
12-27 16:06:13.513 20962 20962 F DEBUG   : ABI: 'arm64'
12-27 16:06:13.513 20962 20962 F DEBUG   : pid: 20871, tid: 20905, name: GLThread 7653  >>> com.chenxf.opengles <<<
12-27 16:06:13.513 20962 20962 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x72006500640069
12-27 16:06:13.513 20962 20962 F DEBUG   :     x0   0072006500640069  x1   0000000000000302  x2   00000000ffffffff  x3   0000007196a37e0c
12-27 16:06:13.513 20962 20962 F DEBUG   :     x4   003d3d3d3d3d204a  x5   0000008000000080  x6   26415e3d44495400  x7   0000000000008036
12-27 16:06:13.513 20962 20962 F DEBUG   :     x8   0072006500640069  x9   0000000000000001  x10  0000000000000003  x11  00000000000000ff

12-27 16:06:13.514 20962 20962 F DEBUG   :
12-27 16:06:13.514 20962 20962 F DEBUG   : backtrace:
12-27 16:06:13.514 20962 20962 F DEBUG   :     #00 pc 0000000000028228  /data/app/com.chenxf.opengles-Xbv907eJgfjlz8Zq9XfKYQ==/base.apk (offset 0x3675000)

3.2 原因分析

スタックがないため、最後にどこで実行されたかを確認するのもログです。コードのリストは次のとおりです。

class TextSample
{
    
    
public:
	TextSample();
	virtual ~TextSample();
	virtual void Init();
	virtual void Draw(int screenW, int screenH);

private:
	Shader *m_pShader;
};



TextSample::TextSample() {
    
    
}

void TextSample::Draw(int screenW, int screenH) {
    
    
    if(m_pShader == nullptr)
        return;

    DEBUG_LOGCATE();
    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    // enable alpha blending
    // ------------
    DEBUG_LOGCATE();

    m_pShader->use();
}

ログは でクラッシュしますm_pShader->use()
しかし、奇妙なことは、関数の前が空であると判断されたことです!if(m_pShader == nullptr) return;

なぜ?m_pShader は定義されているが初期化されていないため
、JAVA とは異なり、C++ の場合、TextSample オブジェクトが生成される限り、内部 m_pShader ポインターは空ではありません!

3.3 ソリューション

解決策は非常に簡単です。コンストラクターで、ポインターが初期化されていることを確認してください。

TextSample::TextSample() {
    
    
    m_pShader = nullptr;
}

これもC++作業とJAVA作業の違い!JAVA はポインタを気にする必要はありません. 変数が定義されており、初期化する必要はありません. デフォルトでは空です.

おすすめ

転載: blog.csdn.net/newchenxf/article/details/121537539