4

I deliberately wrote a code that triggers a null pointer crash,
got this crash log :

libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 27802 (sodino.demo), pid 27802 (sodino.demo)
DEBUG   : ABI: 'arm64'
DEBUG   : Timestamp: 2021-07-17 11:23:28+0800
DEBUG   : pid: 27802, tid: 27802, name: sodino.demo  >>> sodino.demo <<<
DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
DEBUG   : Cause: null pointer dereference
DEBUG   :     x0  0000000000000018  x1  000000707e2e4998  x2  0000000000000019  x3  2073796173207070
DEBUG   :     x4  000000707e2e499e  x5  0000007077a70c58  x6  0000000062626161  x7  0000000063636262
DEBUG   :     x8  0000000000000000  x9  0000000000000000  x10 0000000000000000  x11 0000000000000018
DEBUG   :     x12 6820737961732070  x13 206f74206f6c6c65  x14 0000000000000010  x15 000000711109f39a
DEBUG   :     x16 00000071110a4b58  x17 00000071110082bc  x18 0000007115812000  x19 000000708ee10800
DEBUG   :     x20 0000000000000000  x21 000000708ee10800  x22 0000007fcf67f890  x23 0000007114845658
DEBUG   :     x24 0000000000000004  x25 000000711499c020  x26 000000708ee108b0  x27 0000000000000001
DEBUG   :     x28 0000007fcf67f620  x29 0000007fcf67f5c0
DEBUG   :     sp  0000007fcf67f560  lr  000000707e2cc9b8  pc  000000707e2cc9c8
DEBUG   : 
DEBUG   : backtrace:
DEBUG   :       #00 pc 000000000000c9c8  /data/app/sodino.demo-K1-uQOGzzG20SxiRS9-g1Q==/base.apk!libnative-lib.so (offset 0x1000) (concatenateMyStringWithCppString(char const*)+248) (BuildId: fdb041aba6818c49543f4b4e93c433f6d787c772)
DEBUG   :       #01 pc 000000000000c878  /data/app/sodino.demo-K1-uQOGzzG20SxiRS9-g1Q==/base.apk!libnative-lib.so (offset 0x1000) (Java_sodino_demo_MainActivity_stringFromJNI+32) (BuildId: fdb041aba6818c49543f4b4e93c433f6d787c772)

content in the middel of the log :

what is x0 ~ x29 ? what is sp lr pc ?


Second Question :

#00 pc 000000000000c9c8  
/data/app/sodino.demo-K1-uQOGzzG20SxiRS9-g1Q==/base.apk!
libnative-lib.so (offset 0x1000) 
(concatenateMyStringWithCppString(char const*)+248) 
(BuildId: fdb041aba6818c49543f4b4e93c433f6d787c772)

(concatenateMyStringWithCppString(char const*)+248)
what is meaning of +248 ?

I thought +248 was the code line number,
but the code did not match as below : line 11 trigger the null point crash :

Core.h

#ifndef __HelloCpp__Core__
#define __HelloCpp__Core__

#include <iostream>

const char *concatenateMyStringWithCppString(const char *myString);

#endif /* defined(__HelloCpp__Core__) */

Core.cpp

#include <string.h>
#include "Core.h"

const char *CPP_BASE_STRING = "cpp says hello to %s";

const char *concatenateMyStringWithCppString(const char *myString) {
    char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];
    sprintf(concatenatedString, CPP_BASE_STRING, myString);

    char* p = NULL;
    *p = 0;                    // line 11 crash.
    return concatenatedString;
}

native-lib.cpp

#include <jni.h>
#include <string>
#include "Core.h"

extern "C" JNIEXPORT jstring JNICALL
Java_sodino_demo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    const char* result = concatenateMyStringWithCppString("aabbcc");
//    std::string hello = "Hello from C++";
return env->NewStringUTF(result);
}
Asesh
  • 3,186
  • 2
  • 21
  • 31
Sodino
  • 587
  • 6
  • 16
  • 1
    Looks like you are using M1 based Mac. Those are Arm64 registers: https://developer.arm.com/documentation/102374/0101/Registers-in-AArch64---general-purpose-registers#:~:text=Registers%20in%20AArch64%20%2D%20system%20registers,Data%20processing%20%2D%20extension%20and%20saturation `SP: stack pointer, pc: Program counter and LR: Link register` More: https://developer.arm.com/documentation/ddi0337/h/programmers-model/processor-core-register-summary – Asesh Jul 17 '21 at 03:46
  • Oops I don't use Android but nevertheless they are called registers and those links should be helpful to you. – Asesh Jul 17 '21 at 03:53
  • That number is an offset, you should post the relevant source code along with the arguments used to call that function rather than posting screenshot – Asesh Jul 17 '21 at 04:02
  • @Asesh I edited again. – Sodino Jul 17 '21 at 04:58
  • 1
    `sp`: Stack Pointer, `lr`: Link register (return address), `pc`: program counter (current address of code), `x0`..`x29`: 64-bit general-purpose registers (arm64 arch) – HamidReza Jul 17 '21 at 08:15
  • 1
    backtrace is the `call stack` and `(concatenateMyStringWithCppString(char const*)+248)` means the address of `concatenateMyStringWithCppString(char const*)` plus 248 (as an offset). – HamidReza Jul 17 '21 at 08:23
  • 1
    You should read more about arm64 architecture to know its registers and their applications if you want more details. https://developer.arm.com/documentation/den0024/a/ARMv8-Registers/AArch64-special-registers – HamidReza Jul 17 '21 at 08:27

2 Answers2

2

what is x0 ~ x29 ? what is sp lr pc?

The x0 to x29 are general purpose registers for the ARM64. sp, lr and pc are as described in ARM link and frame pointer.

  • sp the stack pointer used for local data in a function.
  • lr the return address of the function/method that called the current routine.
  • pc the current instruction.

Registers are common to all commercial CPUs. It is possible to make stack base only architectures, but they generally can not perform as well. A compiler can recognize hot values and assign them to registers at build time. Stack is generally 5-100x slower than registers.


(concatenateMyStringWithCppString(char const*)+248) 
(BuildId: fdb041aba6818c49543f4b4e93c433f6d787c772)

what is meaning of +248 ?

This is not at the code level. It is the number of instructions since the start of the routine concatenateMyStringWithCppString. In fact, if all of the routines are not visible to the tracing code,the instruction could be in a different function.

The normal process is to get an assembler listing and it will be (248/4 -> 62) instructions after. Without seeing the assembler,

const char *concatenateMyStringWithCppString(const char *myString) {
    char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];
    sprintf(concatenatedString, CPP_BASE_STRING, myString);

    char* p = NULL;
    *p = 0;                    // line 11 crash.
    return concatenatedString;
}

It looks like line 11 would be about 62 instructions into the routine, especially if strlen() is inlined. Compiler options, versions, etc will change the offset versus line number as they generate different code.

artless noise
  • 21,212
  • 6
  • 68
  • 105
1

what is [the] meaning of +248 ?

It looks like you don't have debug symbols in your binary. Try compiling and linking with -g flag, and you should see source file name and line number in stack traces.

In case of Android, this can be achieved by building with NDK_DEBUG=1 or set android:debuggable="true" in the manifest. See Debuggable versus release builds for more details.

When no debug symbols are available, debug backtraces contain addresses and approximate code locations using function + offset syntax. The offset (+248 in your example) is the address of the failing instruction relative to the start of the function.


what is x0 ~ x29 ? what is sp lr pc?

Those are ARM64 registers. They provide additional details for advanced post-mortem analysis at assembly level. Using the source code in combination with the corresponding assembly and register values at the time of the fault, it's possible to back-track to the root cause of the fault. In your case it's not needed, since the root cause is obvious. In real-life crashes one often has to go up in the code path in order to understand where a null pointer came from.

rustyx
  • 80,671
  • 25
  • 200
  • 267