Приложение аварийно завершает работу при использовании lzo с аргументом -DCMAKE_BUILD_TYPE: STRING = Выпуск на мобильных устройствах Android - PullRequest
0 голосов
/ 23 июня 2019

Я создал проект Android, содержащий код на С ++, использую CMake для компиляции с ++ и использую JNI для связи между с ++ и Java. В файле cpp я использую miniLZO для сжатия файла. Вот код.

TestMiniLzo.cpp

#include <jni.h>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <iterator>
#include "minilzo.h"

std::vector<unsigned char> readFile(const std::string& file);

/* Work-memory needed for compression. Allocate memory in units
 * of 'lzo_align_t' (instead of 'char') to make sure it is properly aligned.
 */


#define HEAP_ALLOC(var,size) \
    lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]

static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS);

std::string testMiniLzo() {
    if (lzo_init() != LZO_E_OK) {
        return "init failed";
    }
    std::vector<unsigned char> fileContents = readFile("/sdcard/testFile");

    // compress with LZO1X-1
    std::vector<unsigned char> compressOutput(fileContents.size() + fileContents.size() / 16 + 64 + 3);
    lzo_uint outSize;
    int r = lzo1x_1_compress(fileContents.data(), fileContents.size(), compressOutput.data(), &outSize, wrkmem);
    if (r != LZO_E_OK) {
        return "fail";
    }
    return "success";
}

std::vector<unsigned char> readFile(const std::string& file) {
    std::ifstream input(file, std::ios::binary);

    // copies all data into buffer
    std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
    return buffer;
}

Это действительно сработало. Никаких ошибок не было. Но все изменилось после того, как я добавил аргумент CMake -DCMAKE_BUILD_TYPE:STRING=Release в build.gradle(app).

externalNativeBuild {
    cmake {
        arguments "-DCMAKE_BUILD_TYPE:STRING=Release"
        cppFlags ""
   }
}

После добавления этого аргумента TestMiniLzo.cpp, показанный выше, продолжал работать на эмуляторе Android x86, но приложение зависало на реальном устройстве Android (Nexus 6), которое имеет архитектуру arm. Вот ошибка.

06-23 10:03:40.962 11229 11229 F libc    : Fatal signal 7 (SIGBUS), code 1, fault addr 0xaad38b85 in tid 11229 (y.myapplication)        
06-23 10:03:40.963   261   261 W         : debuggerd: handling request: pid=11229 uid=10109 gid=10109 tid=11229                         
06-23 10:03:41.033 11276 11276 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***                              
06-23 10:03:41.033 11276 11276 F DEBUG   : Build fingerprint: 'google/shamu/shamu:7.1.1/NGI77B/4345728:user/release-keys'               
06-23 10:03:41.033 11276 11276 F DEBUG   : Revision: '0'                                                                                
06-23 10:03:41.033 11276 11276 F DEBUG   : ABI: 'arm'                                                                                   
06-23 10:03:41.034 11276 11276 F DEBUG   : pid: 11229, tid: 11229, name: y.myapplication  >>> com.body.myapplication <<<                
06-23 10:03:41.034 11276 11276 F DEBUG   : signal 7 (SIGBUS), code 1 (BUS_ADRALN), fault addr 0xaad38b85                                
06-23 10:03:41.034 11276 11276 F DEBUG   :     r0 0a64696f  r1 00000004  r2 a9abb2c0  r3 aad38b85                                       
06-23 10:03:41.034 11276 11276 F DEBUG   :     r4 0000000c  r5 aad38b7d  r6 aad38b85  r7 beedd800                                       
06-23 10:03:41.034 11276 11276 F DEBUG   :     r8 a9abb2a0  r9 a9abb2c0  sl 00000000  fp a9abb2c0                                       
06-23 10:03:41.034 11276 11276 F DEBUG   :     ip 0000001c  sp beedd7c8  lr aad38b70  pc ac71eab0  cpsr 60052430                        
06-23 10:03:41.037 11276 11276 F DEBUG   :                                                                                              
06-23 10:03:41.037 11276 11276 F DEBUG   : backtrace:                                                                                   
06-23 10:03:41.037 11276 11276 F DEBUG   :     #00 pc 00032ab0  /data/app/com.body.myapplication-1/lib/arm/libnative-lib.so (lzo1x_1_com
press+261)                                                                                                                              
06-23 10:03:41.037 11276 11276 F DEBUG   :     #01 pc 00031435  /data/app/com.body.myapplication-1/lib/arm/libnative-lib.so (_Z11testMin
iLzov+128)                                                                                                                              
06-23 10:03:41.038 11276 11276 F DEBUG   :     #02 pc 000325f7  /data/app/com.body.myapplication-1/lib/arm/libnative-lib.so (Java_com_bo
dy_myapplication_MainActivity_compressAndDecompressUsingLzo+26)                                                                         
06-23 10:03:41.038 11276 11276 F DEBUG   :     #03 pc 00276b71  /data/app/com.body.myapplication-1/oat/arm/base.odex (offset 0x249000)
06-23 10:03:41.210 11253 11258 I art     : Do partial code cache collection, code=28KB, data=30KB
06-23 10:03:41.210 11253 11258 I art     : After code cache collection, code=28KB, data=30KB
06-23 10:03:41.210 11253 11258 I art     : Increasing code cache capacity to 128KB

Просто, чтобы дать больше информации, вот мой CMakeLists.txt.

CMakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_subdirectory(minilzo-2.10 "${CMAKE_CURRENT_BINARY_DIR}/minilzo-build")
include_directories(minilzo-2.10)
include_directories(include)

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        TestMiniLzo.cpp
        # Provides a relative path to your source file(s).
        native-lib.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}
        minilzo)

Это /sdcard/testFile, файл для сжатия. Он содержит только пять строк.

android
android
android
android
android

Почему происходит сбой приложения после добавления этого аргумента CMake? Как это исправить?

1 Ответ

1 голос
/ 24 июня 2019

06-23 10: 03: 41.034 11276 11276 F DEBUG: сигнал 7 (SIGBUS), код 1 (BUS_ADRALN), адрес ошибки 0xaad38b85

Эта строка говорит о том, что ваш код выполняет какой-то незаконно выровненный доступ. Это неопределенное поведение в C / C ++. Трассировка стека сообщает вам, где это произошло (06-23 10:03:41.037 11276 11276 F DEBUG : #00 pc 00032ab0 /data/app/com.body.myapplication-1/lib/arm/libnative-lib.so (lzo1x_1_com press+261)).

Почему происходит сбой приложения после добавления этого аргумента CMake?

Поскольку аргумент изменил режим оптимизации для компилятора, из-за чего он выдал другой код, который выявлял эту ошибку. Обычно причина, по которой эта ошибка видна только в некоторых случаях, заключается в том, что некоторые инструкции ARM действительны для чтения / записи без выравнивания, а другие - нет. Выровненные чтения быстрее, когда они действительны, поэтому компилятор будет использовать их, если сможет «доказать», что они есть (с точки зрения компилятора, неопределенное поведение невозможно, поэтому он может «безопасно» использовать эти инструкции, если он появляется что доступ должен быть выровнен).

Как это исправить?

UBSan иногда может уловить эти проблемы, но, к сожалению, не всегда. Добавьте set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") в ваш файл CMakeLists.txt, чтобы включить его, а затем посмотрите на logcat, когда ваше приложение работает.

Если это не поможет, вам нужно проверить код на наличие неопределенного поведения. Наиболее распространенная причина такого рода проблем, с которыми я столкнулся, - это буфер, который выделен как один тип, но доступен как другой. т.е.

char buf[sizeof(Foo) * 10]; // Allocate space for 10 Foo structs.
Foo* foo_array = reinterpret_cast<Foo>(buf);

Приведенный выше код имеет неопределенное поведение, поскольку буфер символов и массив, к которому он приведен, имеют разные требования к выравниванию. Это редко бывает так очевидно, потому что обычно эти ошибки не допускаются в двух смежных строках. Чтобы исправить это, выделите буфер, используя правильный тип, то есть Foo buf[10];.

Для получения дополнительной информации см. https://developer.apple.com/documentation/code_diagnostics/undefined_behavior_sanitizer/misaligned_pointer

...