I have the following code ( from a class member function of mine):
this->mLengOfPath = mFirst->mLengOfPath + mSecond->mLengOfPath;
unsigned short* data = mMiddle->mPathContainer;
mMiddle->mLengOfPath = 0;
for (int index = 0; index < mMiddle->mSize; index++) { //crash here
if (index % 2 == 1 && index > 2){
mMiddle->mLengOfPath +=
GestureUtils::distance(data[index - 3], data[index - 2],
data[index - 1], data[index]);
}
}
In most case, this code doesn't crash. But crashlytics told me that my code "sometimes" crash at line 4, which I don't understand why. If mMiddle is nullptr, it should have crashed at line 2 (I already use mMiddle there).
But crashlytics consistently reports that line 4 is the problem. Anyone know how can my code go wrong at line 4?
Yeah, it's UB, if pointer is invalid. But we have particular platform and compiler in mind, while talking Android NDK and a statistical tool. With native ARM code lines 1,2,4 lines may crash sometimes on invalid pointer, only writing to null pointer is 100% failure.
Line 3 will always fail if mMiddle is null, but may or may not if it points into data segment or not. Statistical tool would highlight line 4 as it is one more often executed one: comparing expression is evaluated on every iteration. Failures on other lines may become statistical noise.
Related
Android app rare production out-of-bounds exception.
My production app sometimes has a rare out-of-bounds-exception crash, which has only ever occurred on a Samsung Galaxy Tab A (2016), 2048 MB RAM, Android 8.1. I cannot properly diagnose which index is OOB. Also I cannot see how any of the indexes can possible be wrong anyway. Am I missing something obvious, can anyone help please?
The app has prod versions 1.0, 1.1, 1.2 & 1.3.
There are crash reports of this happening in v 1.0 on March 30th, and again this week in v 1.2 on May 11th,
Although I could not diagnose it, I attempted some fixes for the 1.0 March 30th crash. These ‘fixes’ are live in version 1.2. So, moving on, 1.2 had a similar crash this week on May 11th (actually 5 crashes over several hours, all on the same device).
The code is:
public Bitmap[][] balloonBitmap = new Bitmap[6][6];
public int[] dynamicObjectRId = new int[10];
for (int j = 1; j <= totalNoOfDynamicImages; j++) {
// PROD CRASH March 30th: OOB was on the next line
**balloonBitmap[correctOptionColourNo][j] = ImageUtil.loadImage(res, db.dynamicObjectRId[j],
dynamicImageWidthQT3, dynamicImageHeightQT3)**;
// PROD CRASH May 11th seems to be on this line:
*byteCountforBitmaps += balloonBitmap[correctOptionColourNo][j].getByteCount();*
}
The fix I tried is done earlier in the method: (live in v1.2)
if ((correctOptionColourNo < 0) || (correctOptionColourNo > 5)) {
correctOptionColourNo = 3;
}
So correctOptionColourNo should be ok, not OOB.
The OOB on May 11th appears to be on the next statement:
byteCountforBitmaps += balloonBitmap[correctOptionColourNo][j].getByteCount();
However, I’m not sure if I can fully believe this, because surely the previous statement would have OOB’d first. Anyway my v 1.2 code backup points to this line of code – I just don’t believe it somehow. But whichever is the actual offending line of code, it’s still the same problem, which index is OOB and why is it happening?
I suspect the problem is here: for (int j = 1; j <= totalNoOfDynamicImages; j++)
Try changing it to for (int j = 0; j < totalNoOfDynamicImages; j++)
The android debug bridge daemon adbd that runs on Android devices may be compiled without root support (ALLOW_ADBD_ROOT=0).
There is a tool called rootadb which is able to patch an existing adbd binary by (as I understood it) replacing the calls to setuid() and setgid() with NOP instructions, effectively preventing it from dropping its privileges.
I don't understand how the code finds the place of the syscalls inside the binary.
As far as I see, it iterates over the all the bytes and checks if the bytes match something:
u32 *sgid = (u32*)&setgid;
int fd = open( "/sbin/adbd", O_RDWR );
fstat( fd, &st );
buf = memalign( 32, st.st_size );
read( fd, buf, st.st_size );
lseek64( fd, 0, SEEK_SET );
for( start = buf, end = start + st.st_size - 0x20; start < end; start++ )
if( !memcmp( &start[1], &sgid[1], sizeof( u32 ) * 2 ) )
memcpy( &start[1], patch, sizeof( patch ) );
How does this work?
With what kind of data are sgid and __setuid actually filled?
I'm not 100% sure, but I have a reasonable idea.
The first line of code loads a pointer to the address of setgid, and treats it as a 32 bit pointer.
The loop iterates over the binary, and looks for occurrences of 8 bytes that equal address of the setgid function. If it finds one, it applies the patch, starting at the first byte of that location.
With what kind of data are sgid and __setuid actually filled?
'u32 *sgid' contains the address of the function 'setgid' and 'u32 *cap' contains the address of 'capset'. __setuid is the function itself but written without the parenthesis '()' we can retrieve the function's address.
I am confident that 0xe3a00000 is not an address to any function's stack frame. And it doesn't point to any location in memory.
With the information given I think 0xe3a00000 in 'patch' is used in the program to restore the state after the sub-routine call and prevent operations that happens after the call,
u32 patch[] =
{
0xe3a00000,
0
};
Below is the snippet that searches and replaces instructions following the call,
for( start = buf, end = start + st.st_size - 0x20; start < end; start++ )
if( !memcmp( &start[1], &sgid[1], sizeof( u32 ) * 2 ) )
memcpy( &start[1], patch, sizeof( patch ) );
Here the next 8 bytes from &sgid[1] should have state information along with the jump instructions to setgid function which is replaced by instruction in patch.
This effectively results in no-op. This is my understanding.
Please check how stack and frame tends to grow in android architecture also about the prologue and epilogue of the functions in this architecture. It will point you in the right direction as to why &sgid[1] (or sgid + 4 bytes) was used.
You could also refer,
https://softwareengineering.stackexchange.com/questions/195385/understanding-stack-frame-of-function-call-in-c-c
https://en.wikipedia.org/wiki/Call_stack#Stack_and_frame_pointers
To learn ARM Neon on Android, I tried to run a sample code.
But I got an error message.
uint16_t in[8] = {0, 1, 2, 3, 4, 5, 6, 7};
uint16_t out[8];
r = vld1q_u16(&in[0]);
**vst1q_u16(&out[0], r);** <-- Here comes an error message
the error message is Invalid Arguments
I don't understand why the problem was.
vld1q_u16 works correctly and the value of r is also correct.
but vst1q_u16 doesn't work.
You should use
r = vld1q_u16(in);
vst1q_u16(out, r);
SIMD engines like NEON read memory contents backwards by default so giving it address of array element 0 is bad idea.
I am recently working on a project aiming at evaluating whether an android app crashes or not. The evaluation process is:
Collect the logs(which record the execution process of an app).
Generate formulas to predict the result (formulas is generated by GP)
Evaluate the logs by formulas
Now I can produce formulas, but for convenience for users, I want to translate formulas into form of natural language and tell users why crash happened.(I think it looks like "inverse natural language processing".)
To explain the idea more clearly, imagine you got a formula like this:
155 - count(onKeyDown) >= 148
It's obvious that if count(onKeyDown) > 7, the result of "155 - count(onKeyDown) >= 148" is false, so the log contains more than 7 onKeyDown event would be predicted "Failed".
I want to show users that if onKeyDown event appears more than 7 times(155-148=7), this app will crash.
However, the real formula is much more complicated, such as:
(< !( ( SUM( {Att[17]}, Event[5]) <= MAX( {Att[7]}, Att[0] >= Att[11]) OR SUM( {Att[17]}, Event[5]) > MIN( {Att[12]}, 734 > Att[19]) ) OR count(Event[5]) != 1 ) > (< count(Att[4] = Att[3]) >= count(702 != Att[8]) + 348 / SUM( {Att[13]}, 641 < Att[12]) mod 587 - SUM( {Att[13]}, Att[10] < Att[15]) mod MAX( {Att[13]}, Event[2]) + 384 > count(Event[10]) != 1))
I tried to implement this function by C++, but it's quite difficult, here's the snippet of code I am working right now.
Does anyone knows how to implement this function quickly?(maybe by some tools or research findings?)Any idea is welcomed :)
Thanks in advance.
my Android 4 app generates long views by adding multiple textviews to a linearlayout. This works well for all my list items, except of one. The problem is, that the list of textviews aborts after adding the first textview, but no exception is thrown!
I just see this warning in my LogCat:
TextLayoutCache | computeValuesWithHarfbuzz -- need to force to single
run
Does anyone know what that means?
HarfBuzz is a layout/shaping engine for OpenType fonts. Its purpose is to standardize text layout in Open-source projects. That warning, can be traced back to android/graphics/TextLayoutCache.cpp.
The relevant code block is:
ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status); //runs the algorithm
int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
if (U_SUCCESS(status) && rc == 1) {
// Normal case: one run, status is ok
isRTL = (paraDir == 1);
useSingleRun = true;
} else if (!U_SUCCESS(status) || rc < 1) {
LOGW("computeValuesWithHarfbuzz -- need to force to single run");
isRTL = (paraDir == 1);
useSingleRun = true;
} else {...}
This part of the code is a part of the BiDi algorithm (uBiDi) which stands for Unicode Bidirectional, as detailed here.
Data in Arabic, Hebrew or another RTL languages need handling of bidirectional text. Because these right-to-left scripts use digits that are written from left to right, the text is actually bidirectional: a mixture of right-to-left and left-to-right text.
rc in the above is the runcount of the algorithm. Each unicode character is assigned a level. (Even the unassigned ones)
Text is first split into different levels, (Level 0 is plain English text, Level 1 is plain Arabic text, possibly embedded within English level 0 text, etc)
The runs now occur in the following manner.
Levels: 0 0 0 1 1 1 2
Runs: <--- 1 ---> <--- 2 ---> <3>
Run count in the above example is 3.
The warning is thrown if the BiDi algorithm hasn't been able to run even once successfully. There are many errors that can occur, preventing the successful running of the algorithm.
Any one of these could've triggered the warning.
However, whether the warning occurs or not, the code behaviour is exactly identical except for the warning logged. So, it shouldn't affect the running of the application.