SIGSEGV, ошибка сегментации, во время выполнения во время выполнения на arm (CortexA9)

#c #go #arm #cgo #clips

#c #Вперед #arm #cgo #клипы

Вопрос:

Что я делаю

Я создаю приложение go, которое должно запускаться на процессоре CortexA9 и использует 3 разные общие библиотеки C / C (я использую оболочку C для вызова кода C ), при вызове одной из них (механизм правил Clips http://www.clipsrules.net /) Я случайно получаю SIGSEGV, Segmentation fault , сама библиотека довольно старая и хорошо протестирована, также тот же код хорошо работает на amd64 arch. Место, где возникает ошибка, выглядит довольно случайным, если я перепишу код, чтобы избежать определенных строк кода, это произойдет в середине другой функции.

Как я создаю библиотеку

Я использую arm-buildroot-linux-gnueabi набор инструментов и arm-buildroot-linux-gnueabihf-gcc как компилятор C, поэтому он построен с помощью этого CFLAGS: -Wall -std=c99 -O3 -fno-strict-aliasing -fPIC -march=armv7-a -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard --sysroot=${some path}

Если я создаю Clips как отдельный двоичный файл (с помощью этого набора инструментов) и выполняю некоторые правила для него, он работает хорошо.

Как я создаю приложение golang

Я создаю приложение на docker golang: 1.16-buster, где находится мой toolchanin

go clean amp;amp; env CGO_CFLAGS="-march=armv7-a -mfpu=neon -mfloat-abi=hard -mtune=cortex-a9 --sysroot={soem path}" CGO_ENABLED=1 GOOS="linux" GOARM=7 GOARCH=arm go build --tags=with_libs,arm -o ./out/$app_name . CC установлен в arm-buildroot-linux-gnueabihf-gcc

Для добавления библиотеки в проект у меня есть arm.go файл:

 //  build arm

package clips

// #cgo LDFLAGS: -L../../libs/arm -lclips -lm -Wl,-rpath -Wl,../libs/arm
import "C"
 

Что вы ожидали увидеть?

Я не ожидаю увидеть никаких неожиданных сигналов.

Что вы увидели вместо этого?

Во время работы приложения, когда я выполняю вызовы cgo из библиотеки so, я получаю это (из gdb): Thread 1 "myapp-arm" received signal SIGSEGV, Segmentation fault.

gdb: обратная трассировка:

     #0  0x76d6fa6c in PrintTemplateFact (theEnv=0x4c8b90, logicalName=0x76d79184 "FactPPForm", theFact=0x4c6dd8, seperateLines=0, ignoreDefaults=0) at /myapp/clips_source/tmpltutl.c:387
    #1  0x76cbfa70 in PrintFact (theEnv=0x4c8b90, logicalName=0x76d79184 "FactPPForm", factPtr=0x4c6dd8, seperateLines=0, ignoreDefaults=0) at /myapp/clips_source/factmngr.c:445
    #2  0x76cbf704 in PrintFactWithIdentifier (theEnv=0x4c8b90, logicalName=0x76d79184 "FactPPForm", factPtr=0x4c6dd8) at /myapp/clips_source/factmngr.c:328
    #3  0x76cc1950 in EnvGetFactPPForm (theEnv=0x4c8b90, buffer=0x535290 "f--1    (attribute (id ) (comment ) (code ) (path", bufferLength=1023, theFact=0x4c6dd8) at /myapp/clips_source/factmngr.c:1590
    #4  0x002661e8 in _cgo_4cadad88d928_Cfunc_EnvGetFactPPForm ()
    #5  0x000823d8 in runtime.asmcgocall () at /usr/local/go/src/runtime/asm_arm.s:596
    #6  0x00a16050 in ?? ()
 

сбой gdb:

 ...
   0x76d6fa3c < 616>:   mov r2, r1
   0x76d6fa40 < 620>:   ldr r1, [r11, #-60] ; 0xffffffc4
   0x76d6fa44 < 624>:   ldr r0, [r11, #-56] ; 0xffffffc8
   0x76d6fa48 < 628>:   bl  0x76c68edc <PrintAtom@plt>
   0x76d6fa4c < 632>:   b   0x76d6fad0 <PrintTemplateFact 764>
   0x76d6fa50 < 636>:   ldr r3, [r11, #-8]
   0x76d6fa54 < 640>:   lsl r3, r3, #3
   0x76d6fa58 < 644>:   ldr r2, [r11, #-24] ; 0xffffffe8
   0x76d6fa5c < 648>:   add r3, r2, r3
   0x76d6fa60 < 652>:   ldr r3, [r3, #4]
   0x76d6fa64 < 656>:   str r3, [r11, #-28] ; 0xffffffe4
   0x76d6fa68 < 660>:   ldr r3, [r11, #-28] ; 0xffffffe4
=> 0x76d6fa6c < 664>:   ldr r3, [r3, #4]
   0x76d6fa70 < 668>:   cmp r3, #0
   0x76d6fa74 < 672>:   ble 0x76d6fad0 <PrintTemplateFact 764>
   0x76d6fa78 < 676>:   ldr r3, [pc, #232]  ; 0x76d6fb68 <PrintTemplateFact 916>
   0x76d6fa7c < 680>:   add r3, pc, r3
   0x76d6fa80 < 684>:   mov r2, r3
   0x76d6fa84 < 688>:   ldr r1, [r11, #-60] ; 0xffffffc4
   0x76d6fa88 < 692>:   ldr r0, [r11, #-56] ; 0xffffffc8
   0x76d6fa8c < 696>:   bl  0x76c68c3c <EnvPrintRouter@plt>
   0x76d6fa90 < 700>:   ldr r3, [r11, #-8]
...
 

Редактировать:

Я даже могу получить SEGFAULT с помощью этого кода:

 func SelfHealthCheck(deftemplate string) {
    env := C.CreateEnvironment()

    // Create deftemplate
    cconstruct := C.CString(deftemplate)
    defer C.free(unsafe.Pointer(cconstruct))
    if C.EnvBuild(env, cconstruct) != 1 {
        log.Println("error")
        return
    }

    // Obtain pointer on it
    cname := C.CString("attribute")
    defer C.free(unsafe.Pointer(cname))
    tplptr := C.EnvFindDeftemplate(env, cname)
    if tplptr == nil {
        log.Println("error")
        return
    }

    // Create fact
    factptr := C.EnvCreateFact(env, tplptr)

    // print it
    var bufsize C.size_t = 1024
    buf := (*C.char)(C.malloc(C.sizeof_char * bufsize))
    defer C.free(unsafe.Pointer(buf))
    C.EnvGetFactPPForm(env, buf, bufsize-1, unsafe.Pointer(factptr))
    log.Infoln(C.GoString(buf))
}
 

Комментарии:

1. Похоже theFact->theProposition , что значение было нулевым (или недействительным).

2. Звучит как обычная старая ошибка неопределенного поведения. Опубликуйте этот PrintTemplateFact источник.

3. Это не null, оно ссылается на недопустимый адрес памяти, и тот же код работает на amd64 arch.

4. метод @Lundin довольно большой, и он работает, когда Clips компилируется как двоичный файл stabdalone. Но в любом случае: pastebin.com/NRfiGHTp

5. кстати, исходники clips доступны здесь: sourceforge.net/projects/clipsrules/files/CLIPS/6.31 но, как я уже упоминал, это старый и хорошо проверенный проект.