短信识别报错


报错堆栈

pid: 4877, tid: 5960, name: Binder_6  >>> com.huawei.systemmanager:service <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    r0 d93c6528  r1 00000000  r2 32373031  r3 00373539
    r4 cabbc6a0  r5 d93c6520  r6 ffffffff  r7 00000000
    r8 00000000  r9 d8f59b1c  sl d8f59fc8  fp d8f59804
    ip d93c6520  sp d75d2b30  lr eeae63e9  pc f7390620  cpsr a00f0010

backtrace:
    #00 pc 00018620  /system/lib/libc.so (strcmp+52)
    #01 pc 0000e3e5  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (compareSender+24) Bumblebee/jni/rule_sender.c:62
    #02 pc 0002ac51  /system/lib/libc.so (qsort+272)
    #03 pc 0000e65d  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (decodeSender+196) Bumblebee/jni/rule_sender.c:217
    #04 pc 0000f939  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (parseFeature+36)
    #05 pc 0000fb9d  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (InitFeature+440)
    #06 pc 0000fc73  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (InitSmsChecker+34)
    #07 pc 00007013  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (init_sms_checker+30)
    #08 pc 002896b5  /system/framework/oat/arm/com.huawei.systemmanager.separated.odex (offset 0x1f4000)

报错堆栈为使用c标准库函数qsort快速排序时出现的问题,快速排序的对象为空指针.

通过转换到代码行号,查找到对应的代码

rule_sender.c

<?prettify linenums=173?>

int decodeSender(POSEIDONFeature *feature)
{
    int ret = PDSYSERROR;
    JceInputStream* is = NULL;
    POSEIDONSender *sender = NULL;
    do
    {
        is = JceInputStreamnew();
        PDASSERTNOTNULL(is, ret);
 
        JceInputStreamreset(is);
        JceInputStreamsetBuffer(is, JStringdata(feature->data), JStringsize(feature->data));
 
        sender = POSEIDONSendernew();
        PDASSERTNOTNULL(sender, ret);
 
        ret = POSEIDONSenderreadFrom(sender, is);
        if(ret != JCESUCCESS)
        {
            ret = PDSYSERROR;
            break;
        }
 
        grulesendercount = JArraysize(sender->val);
        if(grulesendercount <= 0)
        {
            ret = PDSYSERROR;
            break;
        }
 
        grulesender = (POSEIDONStringKeyVal **)calloc(grulesendercount, sizeof(POSEIDONStringKeyVal *));
        PDASSERTNOTNULL(grulesender, ret);
 
        int i = 0;
        for(i=0;i<grulesendercount;i++)
        {
            grulesender[i] = POSEIDONStringKeyValnew();
 
            JceInputStreamreset(is);
            JceInputStreamsetBuffer(is, JArraygetPtr(sender->val, i), JArraygetLength(sender->val, i));
 
            JceInputStreamreadStruct(is, grulesender[i], 0, true);
        }
 
        qsort(grulesender, grulesendercount, sizeof(POSEIDONStringKeyVal *), compareSender);
 
        ret = PDSUCC;
 
    }while(0);
 
    POSEIDONSenderfree(&sender);
    JceInputStreamfree(&is);
 
    return 0;
}

报错对应的位置为217行的qsort,继续看compareSender的实现位置

rule_sender.c

<?prettify linenums=57?>

int compareSender(const void *node1, const void *node2)
{
      POSEIDONStringKeyVal *ptr1 = *(POSEIDONStringKeyVal * const *)node1;
      POSEIDONStringKeyVal *ptr2 = *(POSEIDONStringKeyVal * const *)node2;
 
      return strcmp(JStringdata(ptr1->k), JStringdata(ptr2->k));
}

最终报错的位置为62行的strcmp,说明ptr1->kptr2->k之一或全部为NULL

这里的cmp对象从上一函数看是

typedef struct POSEIDON_StringKeyVal POSEIDON_StringKeyVal;
struct POSEIDON_StringKeyVal
{
    char * className;
    Int32 (*writeTo)( const POSEIDON_StringKeyVal*, JceOutputStream *);
    Int32 (*readFrom)( POSEIDON_StringKeyVal*, JceInputStream *);
    JString *  k;
    Float v;
    Float r;
    JArray *  classify;
    Int32 index;
};

成员变量k在这里看样子是作为key使用,在同一文件的查找中看以如下代码

rule_sender.c

<?prettify linenums=229?>

int SenderBinarySearch(POSEIDONStringKeyVal **rulesender, const char* key, int low, int high)
{
  if(rulesender == NULL)
    return -1;
 
  while(low <= high)
  {
    int index = (low+high)/2;
    int diff = strcmp(JStringdata(rule_sender[index]->k), key);
    if(diff == 0)
      return index;
    else
      if(diff < 0)
      {
        low = index +1;
      }
      else
      {
        high = index -1;
      }
   }
  return -2; 
}

综上,直接在strcmp中判空跳过,会导致后面在使用这个数据结构时再次出错.

这里在生成这个数组的时候直接判断,如果成员为空,这个对象将不会被加入数组中.

详细修改为:revison 293643

另一报错

LOG:
pid: 5587, tid: 5596, name: FinalizerDaemon  >>> com.huawei.systemmanager:service <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
    r0 00000000  r1 e34f64f8  r2 00000008  r3 00000640
    r4 cbd50e40  r5 00000191  r6 135f1b40  r7 12c05040
    r8 70f8c7e8  r9 eddc4800  sl 1309f9d0  fp 135f1b40
    ip e34f6048  sp f3aeb538  lr ee0c740d  pc ee0c3ab6  cpsr 800f0030
 
backtrace:
    #00 pc 0000aab6  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (POSEIDON_StringKeyVal_del+5) jni_branchs\Bumblebee/jni/poseidon.c:316
    #01 pc 0000e409  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (releaseSender+24) jni_branchs\Bumblebee/jni/rule_sender.c:75
    #02 pc 0000fccb  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (FinishSmsChecker+6) jni_branchs\Bumblebee/jni/sms_checker.c:362
    #03 pc 0000702f  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (finish_sms_checker+2) jni_branchs\Bumblebee/jni/bumblebee.c:20
    #04 pc 0020105f  /system/framework/oat/arm/com.huawei.systemmanager.separated.odex (offset 0x1b4000)

poseidon.c

<?prettify linenums=313?>

void POSEIDONStringKeyValdel(POSEIDONStringKeyVal ** handle)
{
    POSEIDONStringKeyVal ** this = (POSEIDONStringKeyVal*)handle;
    if((this)->k) JStringdel(&(this)->k);
    if((this)->classify) JArray_del(&(this)->classify);
    if((this)->className) JceFree((this)->className);
    JceFree(this);
    *this = NULL;
}

报错的地址为 fault addr 0xc,这个值很接近空指针,进一步分析出错的代码316行是对一个数据结构区成员变量,这个数据结构的定义如下

poseidon.h

<?prettify linenums=313?>

typedef struct POSEIDONStringKeyVal POSEIDONStringKeyVal;
struct POSEIDONStringKeyVal
{
    char * className;
    Int32 (*writeTo)( const POSEIDONStringKeyVal*, JceOutputStream );
    Int32 (readFrom)( POSEIDON_StringKeyVal*, JceInputStream *);
    JString *  k;
    Float v;
    Float r;
    JArray *  classify;
    Int32 index;
};

可以看到当handleNULL时对应的k的地址正是0xc,所以这个地方肯定是handleNULL导致的问题,具体在代码的逻辑中是因为什么逻辑导致了handleNULL由于时间关系暂没有深究, 这里使用防御性的手段对handle进行判空保护.

修改如下

又一报错~~o(>_<)o ~~

Crash LOG:

    signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
    r0 d9531800  r1 d95318f8  r2 d95319f0  r3 00000000
    r4 00000000  r5 d95319f0  r6 f32eb3d5  r7 d9531800
    r8 00000000  r9 d9531fc8  sl 12c0a280  fp d9531804
    ip f32f8f94  sp d92c0b20  lr f747bb09  pc f32eb3da  cpsr 80000030

 

backtrace:

    #00 pc 0000e3da  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (compareSender+5) jni_branchs\Bumblebee/jni/rule_sender.c:62
    #01 pc 0002ab07  /system/lib/libc.so (med3.isra.1+10)
    #02 pc 0002abe5  /system/lib/libc.so (qsort+164)
    #03 pc 0000e699  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (decodeSender+248) jni_branchs\Bumblebee/jni/rule_sender.c:230
    #04 pc 0000f979  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (parseFeature+36)  jni_branchs\Bumblebee/jni/sms_checker.c:129
    #05 pc 0000fbdd  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (InitFeature+440)  jni_branchs\Bumblebee/jni/sms_checker.c:315
    #06 pc 0000fcb3  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (InitSmsChecker+34)jni_branchs\Bumblebee/jni/sms_checker.c:354
    #07 pc 00007013  /system/priv-app/HwSystemManager/lib/arm/libbumblebee-1.0.0-mfr.so (init_sms_checker+30) jni_branchs\Bumblebee/jni/bumblebee.c:15
typedef struct POSEIDON_Sender POSEIDON_Sender;
struct POSEIDON_Sender
{
    char * className;
    Int32 (*writeTo)( const POSEIDON_Sender*, JceOutputStream *);
    Int32 (*readFrom)( POSEIDON_Sender*, JceInputStream *);
    JArray *  val;

};

Int32 POSEIDON_Sender_readFrom(POSEIDON_Sender* taf_st, JceInputStream *is)
{
    Int32 ret=0;
    ret = JceInputStream_readVector(is, taf_st->val, 0, true);
    if(JCE_SUCCESS != ret) return ret;

    return JCE_SUCCESS;
}
typedef struct POSEIDON_FeatureList POSEIDON_FeatureList;
struct POSEIDON_FeatureList
{
    char * className;
    Int32 (*writeTo)( const POSEIDON_FeatureList*, JceOutputStream *);
    Int32 (*readFrom)( POSEIDON_FeatureList*, JceInputStream *);
    JArray *  val;
    Float threshold;
    Float symbol_threshold;

};

POSEIDON_FeatureList * POSEIDON_FeatureList_new()
{
    Int32 ret=0;
    POSEIDON_FeatureList *this = (POSEIDON_FeatureList *)JceMalloc(sizeof(POSEIDON_FeatureList));
    if(!this) return NULL;
    ret = POSEIDON_FeatureList_init(this);
    if(JCE_SUCCESS != ret) { return NULL; }
    return this;
}

Int32 POSEIDON_FeatureList_init(POSEIDON_FeatureList * handle)
{
    POSEIDON_FeatureList * this = (POSEIDON_FeatureList*) handle;

    char * tafClassName = "POSEIDON.FeatureList";

    this->className = JceMalloc(strlen(tafClassName)+1);
    this->writeTo = POSEIDON_FeatureList_writeTo;
    this->readFrom = POSEIDON_FeatureList_readFrom;

    this->val = JArray_new("POSEIDON.Feature");
    this->threshold = 0;
    this->symbol_threshold = 0;

    if(!this->className  || !this->val)
    {
        POSEIDON_FeatureList_del(&this);
        return JCE_MALLOC_ERROR;
    }
    memcpy(this->className, tafClassName, strlen(tafClassName)+1);


    return JCE_SUCCESS;
}

Int32 POSEIDON_FeatureList_readFrom(POSEIDON_FeatureList* taf_st, JceInputStream *is)
{
    Int32 ret=0;
    ret = JceInputStream_readVector(is, taf_st->val, 0, true);
    if(JCE_SUCCESS != ret) return ret;
    ret = JceInputStream_readFloat(is, &taf_st->threshold, 1, false);
    if(JCE_SUCCESS != ret) return ret;
    ret = JceInputStream_readFloat(is, &taf_st->symbol_threshold, 2, false);
    if(JCE_SUCCESS != ret) return ret;

    return JCE_SUCCESS;
}
Int32 JceInputStream_readVector(JceInputStream * is, JArray* v, uint8_t tag, Bool isRequire)
{
    Int32 ret = JceInputStream_checkValid(is,tag,isRequire);
    if (JCE_DECODE_EOPNEXT == ret) return JCE_SUCCESS;
    if (JCE_SUCCESS != ret) return ret;

    switch (DataHead_getType(is->_h))
    {
    case eList:
        {
            Int32 size, i;
            ret = JceInputStream_readInt32(is, &size, 0, true);
            if (JCE_SUCCESS != ret) return ret;

            if (size < 0)
            {
                snprintf(is->_err, sizeof(is->_err), "invalid size, tag: %d, type: %d, size: %d", tag, DataHead_getType(is->_h), size);
                return JCE_DECODE_ERROR;
            }
            for (i = 0; i < size; ++i)
            {
                uint32_t p1, p2;
                p1 = is->_cur;
                ret = JceInputStream_skipField(is);
                if (JCE_SUCCESS != ret) return ret;

                p2 = is->_cur;

                ret = JArray_pushBack(v, JString_data(is->_buf)+p1, p2-p1);
                if (JCE_SUCCESS != ret) return ret;
            }
        }
        break;
    default:
        {
            snprintf(is->_err, sizeof(is->_err), "read 'vector' type mismatch, tag: %d, get type: %d.", tag, DataHead_getType(is->_h));
            return JCE_DECODE_ERROR;
        }
    }
    return JCE_SUCCESS;
}
//数组封装
struct JArray
{
    char *   elem_type_name;//类型名称
    unsigned elem_num;
    unsigned list_len;
    int *    list;
    unsigned buff_used;
    unsigned buff_len;
    char *   buff;          //元素的jce编码结果
};

JArray * JArray_new(const char * type)
{
    unsigned len = 0;
    JArray * arr = JceMalloc(sizeof(JArray));
    if (!arr)
        return NULL;

    JArray_init(arr);

    len = strlen(type);
    arr->elem_type_name = JceMalloc(len+1);
    if (!arr->elem_type_name)
    {
        JceFree(arr);
        return NULL;
    }

    memcpy(arr->elem_type_name, type, len+1);

    return arr;
}
void JArray_init(JArray *arr)
{
/*
    arr->elem_type_name = NULL;
    arr->elem_num       = 0;
    arr->list_len       = 0;
    arr->list           = NULL;
    arr->buff_used      = 0;
    arr->buff_len       = 0;
    arr->buff           = NULL;
  */ 
    memset(arr, 0, sizeof(JArray));
}
int JArray_size(JArray *arr)
{
    if (arr == NULL) 
        return 0;
    return arr->elem_num;
}

char *JArray_getPtr(JArray *arr, unsigned index)
{
    if (arr == NULL || (Int32)index < 0)
        return NULL;

    if (index > arr->elem_num - 1)
    {
        return NULL;
    }

    return arr->buff + arr->list[index];
}
char * JString_data(JString *s)         { if (s) return s->_data; return NULL;}
uint32_t JString_size(JString *s)       { if (s) return s->_len; return 0;}

//string封装
struct JString
{
    char *        _data;
    unsigned int  _len;
    unsigned int  _buf_len;
};
JString * JString_new()
{
    Int32 ret;
    JString *s = JceMalloc(sizeof(JString));
    if (!s)
        return NULL;

    ret = JString_init(s);
    if (ret)
    {
        JceFree(s);
        return NULL;
    }

    return s;
}

Int32 JString_init(JString *s)
{
    if (s == NULL)
        return JCE_MALLOC_ERROR;

    s->_data = JceMalloc(1);
    if (!s->_data)
        return JCE_MALLOC_ERROR;

    s->_data[0] = 0;
    s->_len  = 0;
    s->_buf_len = 1;

    return JCE_SUCCESS;
}

typedef struct POSEIDON_Feature POSEIDON_Feature;
struct POSEIDON_Feature
{
    char * className;
    Int32 (*writeTo)( const POSEIDON_Feature*, JceOutputStream *);
    Int32 (*readFrom)( POSEIDON_Feature*, JceInputStream *);
    Int32 type;
    JString *  data;

};

POSEIDON_Feature * POSEIDON_Feature_new()
{
    Int32 ret=0;
    POSEIDON_Feature *this = (POSEIDON_Feature *)JceMalloc(sizeof(POSEIDON_Feature));
    if(!this) return NULL;
    ret = POSEIDON_Feature_init(this);
    if(JCE_SUCCESS != ret) { return NULL; }
    return this;
}

Int32 POSEIDON_Feature_init(POSEIDON_Feature * handle)
{
    POSEIDON_Feature * this = (POSEIDON_Feature*) handle;

    char * tafClassName = "POSEIDON.Feature";

    this->className = JceMalloc(strlen(tafClassName)+1);
    this->writeTo = POSEIDON_Feature_writeTo;
    this->readFrom = POSEIDON_Feature_readFrom;

    this->data = JString_new();

    if(!this->className  || !this->data)
    {
        POSEIDON_Feature_del(&this);
        return JCE_MALLOC_ERROR;
    }
    memcpy(this->className, tafClassName, strlen(tafClassName)+1);


    return JCE_SUCCESS;
}

Int32 JceInputStream_readStruct(JceInputStream * is, void * st, uint8_t tag, Bool isRequire)
{
    Int32 ret=0;
    const JStructBase* jst = st; 
    JString *s = JString_new();
    JceInputStream *i = JceInputStream_new();
    do
    {
        if (!s || !i)
        {
            ret = JCE_MALLOC_ERROR; break;
        }
        ret = JceInputStream_readStructString(is, s, tag, isRequire);
        if ( JCE_SUCCESS != ret ) break;
        ret= JceInputStream_setBuffer(i, JString_data(s), JString_size(s));
        if ( JCE_SUCCESS != ret ) break;
        ret = jst->readFrom(st, i);
    }while (0);
    if (s) JString_del(&s);
    if (i) JceInputStream_del(&i);
    return ret;
}
Int32 POSEIDON_Feature_readFrom(POSEIDON_Feature* taf_st, JceInputStream *is)
{
    Int32 ret=0;
    ret = JceInputStream_readInt32(is, & taf_st->type, 0, true);
    if(JCE_SUCCESS != ret) return ret;
    ret = JceInputStream_readVectorChar(is, taf_st->data, 1, true);
    if(JCE_SUCCESS != ret) return ret;

    return JCE_SUCCESS;
}

Copyright © FengGuangtu 2017