Operator new does not throw bad_alloc on Android - android

I am developing a C++ game on Android NDK (android-ndk-r9b). If I write this:
class Test
{
char c[1024*1024*1024];
};
//in main
try {
Test* p;
while (1) {
p = new Test();
}
} catch (bad_alloc) {
cout << "bad_alloc\n";
}
it doesn't throw. If I try this:
void no_memory_by_new() {
cout << "no_memory_by_new\n";
throw bad_alloc();
}
//in main
set_new_handler(no_memory_by_new);
Test* p;
while (1) {
p = new Test();
}
it doesn't work either. Finally, if I try this:
//in main
set_new_handler(no_memory_by_new);
int* p;
while (1) {
p = new int[1024*1024*1024];
}
then no_memory_by_new is called. I'm really confused about this. Can anyone help me?

This is bug in Android build of GNU libstdc++. If you look into operator new implementation, you'll see it call _GLIBCXX_THROW_OR_ABORT if malloc return NULL. Next, if you look on definition of _GLIBCXX_THROW_OR_ABORT, you'll see it throw bad_alloc only if __EXCEPTIONS defined; otherwise, it just call abort. For some reason, __EXCEPTIONS macro is not defined in Android build of GNU libstdc++, so it call abort - exactly what you see in your case.
I've checked this behaviour with both Android NDK r10d and CrystaX NDK 10.1 - and it's the same in both cases. I've filed ticket to fix this in CrystaX NDK. For fixing that in Google's NDK, you should also file ticket in Google's NDK bug tracker
UPD: It seems that situation is not so simple... Investigating it further, I've found more details pointing to the fact there is something bit more complicated than I've described above. Looking further; will update answer when have strict results.
UPD2: After deep investigation I've found that my previous answer was completely wrong. In fact, __EXCEPTIONS are defined when building GNU libstdc++, so operator new actually throw bad_alloc if malloc return NULL. The problem is in your code actually, but it was bit tricky to figure out. See explanation below.
TL;DR: operator new return pointer to the "allocated" memory (so from its point of view, there's no reason to throw std::bad_alloc), but first access to that memory cause crash because actually those pages are not available.
More detailed explanation:
Here is complete code I've used for testing:
#include <new>
#include <stdio.h>
#include <string.h>
class Test
{
public:
Test() {
::fprintf(stderr, "ctor start\n");
//memset(c, 0, sizeof(c));
::fprintf(stderr, "ctor finish\n");
}
private:
char c[1024*1024*1024];
};
int main()
{
try {
while (1) {
Test *p = new Test();
if (!p)
return 1;
}
return 1;
} catch (std::bad_alloc) {
return 0;
}
}
If you compile this test and run it on device, you'll get std::bad_alloc on some iteration (I get it on third iteration). But if you uncomment memset in constructor of Test, application will crash on the first memset call. If you remove constructor of Test completely, it will crash too - just because in this case compiler will generate constructor, which do zero-initialization of all members - i.e. the same as we do with memset.
The difference here is that malloc (used internally in operator new) returns pointer to the "allocated" memory, but actually it is not allocated; this region is just marked as "need to be allocated in future, when application will actually refer it". This is how Linux kernel handle it, for performance reasons. On next step, when you (or compiler) fill array with zeros, application actually access those pages but, unfortunately, there's just no free memory in system, so Linux kernel call OOM killer, killing the process as result.
This is not Android-specific. In fact, the same happens on GNU/Linux systems; the only difference is amount of memory available to the system (on Android it much lower than on servers, for obvious reasons).

In order to have working exceptions, you need to build using one of the other C++ standard libraries, other than the default one. Add e.g. APP_STL := gnustl_static to jni/Application.mk. Additionally, you need to enable exceptions, add LOCAL_CPP_FEATURES += exceptions to your Android.mk, or add APP_CPPFLAGS += -fexceptions to jni/Application.mk.

Related

Bug in QtLocation/Android? JNI_OnLoad never called -> crash on nullpointer access

I've been investigating on a Qt5/Android/Location issue and found a nullpointer access which makes me think GPS with Qt5 cannot work on any machine.
In my case when I try to run
auto source = QGeoPositionInfoSource::createDefaultSource(this);
the method AttachedJNIEnv::AttachedJNIEnv() defined in src/plugins/position/android/src/jnipositioning.cpp (Qt5 sources) crashes with the following call:
if (javaVM->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) {
On at least three devices I've tried, javaVM is NULL so I'm pretty sure it's not just an issue with my device.
javaVM is a global pointer (what a shame..) and it should get a value in Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *, void *) also defined in jnipositioning.cpp
My question is now:
Obviously this is a bug in Qt5 and I'll make a bug report. But in the meanwhile I'd like to get positioning working with some sort of fix/workaround.
So what can be the reason for JNI_OnLoad() not being called? Did I forget to somehow initialize Qt::Location? Who should call JNI_OnLoad()? Can I do this manually in some way?
Update:
I've reported a Qt bug now.

Does android support the PTRACE_SINGLESTEP?

OK, this is a simple question.Does android support the PTRACE_SINGLESTEP when I use ptrace systemcall? when I want to ptrace a android apk program, I find that I can't process the SINGLESTEP trace. But the situation changed when I use the PTRACE_SYSCALL, It can work perfectly. Does the android wipe out this function or arm lack some supports in hardware? Any help will be appreciated!thanks.
this is my core program:
int main(int argc, char *argv[])
{
if(argc != 2) {
__android_log_print(ANDROID_LOG_DEBUG,TAG,"please input the pid!");
return -1;
}
if(0 != ptrace(PTRACE_ATTACH, target_pid, NULL, NULL))
{
__android_log_print(ANDROID_LOG_DEBUG,TAG,"ptrace attach error");
return -1;
}
__android_log_print(ANDROID_LOG_DEBUG,TAG,"start monitor process :%d",target_pid);
while(1)
{
wait(&status);
if(WIFEXITED(status))
{
break;
}
if (ptrace(PTRACE_SINGLESTEP, target_pid, 0, 0) != 0)
__android_log_print(ANDROID_LOG_DEBUG,TAG,"PTRACE_SINGLESTEP attach error");
}
ptrace(PTRACE_DETACH, target_pid, NULL, NULL);
__android_log_print(ANDROID_LOG_DEBUG,TAG,"monitor finished");
return 0;
}
I run this program on shell. And I can get the root privilege.
If I change the request to PTRACE_SYSCALL the program will run normally.
But if the request is PTRACE_SINGLESTEP, the program will get an error!
PTRACE_SINGLESTEP has been removed on ARM Linux since 2011, by this commit.
The HW has no support for single-stepping; previous kernel support involved decoding the instruction to figure out which one's next (branches) and temporarily replacing it with a debug-break software breakpoint.
Quoting a mailing list message about the same commit, describing the old situation: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-February/041324.html
PTRACE_SINGLESTEP is a ptrace request designed to offer single-stepping
support to userspace when the underlying architecture has hardware
support for this operation.
On ARM, we set arch_has_single_step() to 1 and attempt to emulate
hardware single-stepping by disassembling the current instruction to
determine the next pc and placing a software breakpoint on that
location.
Unfortunately this has the following problems:
Only a subset of ARMv7 instructions are supported
Thumb-2 is unsupported
The code is not SMP safe
We could try to fix this code, but it turns out that because of the
above issues it is rarely used in practice. GDB, for example, uses
PTRACE_POKETEXT and PTRACE_PEEKTEXT to manage breakpoints itself and
does not require any kernel assistance.
This patch removes the single-step emulation code from ptrace meaning
that the PTRACE_SINGLESTEP request will return -EIO on ARM. Portable
code must check the return value from a ptrace call and handle the
failure gracefully.
Signed-off-by: Will Deacon <will.deacon at arm.com>
---
The comments I received about v1 suggest that:
If emulation is required, it is plausible to do it from userspace
ltrace uses the SINGLESTEP call (conditionally at compile-time since other architectures, such as mips, do not support this
request) but does not check the return value from ptrace. This is a
bug in ltrace.
strace does not use SINGLESTEP

Android ndk-r9 compiler optimization issues

I recently switched to using Android ndk-r9 and am having some difficulty with my app that seems to be related to compiler optimization. I have the following function:
int GetTouchPos(GTouchEvents * pEvents, GPointF * pPos, int * pButton = 0)
{
int count = 0;
GTouchEvent * pEvent;
if (pEvents->GetCount(&count) == GResult_Ok)
{
GDebugLog((GS("GetTouchPos: count = %d"), count));
if (pEvents->GetEvent(0, &pEvent) == GResult_Ok)
{
pEvent->GetTapPos(pPos);
if (pButton)
{
pEvent->GetButton(pButton);
}
pEvent->Release();
}
}
return(count);
}
If I build my project and run it, the call to GDebugLog formats and logs the value of the variable 'count'. When I do this, 'count' is 1 and my app works correctly. However if I comment out the GDebugLog line (and make NO other changes), when I run my app, it no longer works. In the function GTouchEvents::GetCount, I also am logging what it is returning and the value is always correctly '1'. Also, I log the return from the call to the function above (i.e. GetTouchPos). When the GDebugLog line is present, the logged return value is the correct value '1'. However when I comment out the GDebugLog call, the logged return value is a seemingly random number, which looks suspiciously like an uninitialized variable.
Note that this all works with our without the GDebugLog line when I was using r8b. Also note that if I turn optimization off, this code works perfectly using r9 whether the debugging line is present or not. Also note that this behavior only presents itself when compiling for the ARM processor. The version I build for x86 works without problem.
Am I doing something questionable here that is causing the optimizer to generate incorrect code?
Can anyone shed some light on what might be happening?
Thanks.

JNI getmethodID returns NULL only in ICS but not in Gingerbread

I'm currently porting Gingerbread code to ICS. The communication between C and Java happens properly in Gingerbread. But the same thing crashes in ICS. Not able to figure out.
What are the major changes in ICS jni.?
My current problem,
1.Get the Class Instance and convert it into global reference and store it.
jclass myWrapperClass = (*env)->FindClass(env,"com/test/mypackage/Wrapper");
if (voipWrapperClass == NULL) {
// error - handling and returns
}
WrapperClass = (jclass)(*env)->NewGlobalRef(env,myWrapperClass);
2.From a JNI call the flow goes to below stack and returns callback to jni. From JNI to java the below function call
void response(void* ptr, int result){
JNIEnv *envPtr= NULL;
JavaVM* vmPtr= p_pdb->vm;
if ((*vmPtr)->GetEnv(vmPtr,(void**) &envPtr, JNI_VERSION_1_4) == JNI_EDETACHED) {
(*vmPtr)->AttachCurrentThread(vmPtr,(void**)&envPtr,NULL);
}
if (ptr->WrapperClass == NULL) {
// error- handling and return
}
RespMethodId = (*envPtr)->GetMethodID(envPtr,ptr->WrapperClass, "resp","(Z)V");
// this method is always 0 ... prev for gingerbread it returned a valid id..
}
Please give me a solution how to proceed further.?
I have found the solution finally. I used to compile my code in android code-base (2.3.3) but from ICS if you need to build a separate shared library use NDK and build a separate library. Else place the code in frameworks folder. This solves the problem. :)

Android preprocessor macros with 2 targets [duplicate]

I doubt if there is a way to make compile-time conditions in Java like #ifdef #ifndef in C++.
My problem is that have an algorithm written in Java, and I have different running time improves to that algorithm. So I want to measure how much time I save when each improve is used.
Right now I have a set of boolean variables that are used to decide during the running time which improve should be used and which not. But even testing those variables influences the total running time.
So I want to find out a way to decide during the compilation time which parts of the program should be compiled and used.
Does someone knows a way to do it in Java. Or maybe someone knows that there is no such way (it also would be useful).
private static final boolean enableFast = false;
// ...
if (enableFast) {
// This is removed at compile time
}
Conditionals like that shown above are evaluated at compile time. If instead you use this
private static final boolean enableFast = "true".equals(System.getProperty("fast"));
Then any conditions dependent on enableFast will be evaluated by the JIT compiler. The overhead for this is negligible.
javac will not output compiled code that is unreachable. Use a final variable set to a constant value for your #define and a normal if statement for the #ifdef.
You can use javap to prove that the unreachable code isn't included in the output class file. For example, consider the following code:
public class Test
{
private static final boolean debug = false;
public static void main(String[] args)
{
if (debug)
{
System.out.println("debug was enabled");
}
else
{
System.out.println("debug was not enabled");
}
}
}
javap -c Test gives the following output, indicating that only one of the two paths was compiled in (and the if statement wasn't):
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String debug was not enabled
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
I think that I've found the solution, It's much simpler.
If I define the boolean variables with "final" modifier Java compiler itself solves the problem. Because it knows in advance what would be the result of testing this condition.
For example this code:
boolean flag1 = true;
boolean flag2 = false;
int j=0;
for(int i=0;i<1000000000;i++){
if(flag1)
if(flag2)
j++;
else
j++;
else
if(flag2)
j++;
else
j++;
}
runs about 3 seconds on my computer.
And this one
final boolean flag1 = true;
final boolean flag2 = false;
int j=0;
for(int i=0;i<1000000000;i++){
if(flag1)
if(flag2)
j++;
else
j++;
else
if(flag2)
j++;
else
j++;
}
runs about 1 second. The same time this code takes
int j=0;
for(int i=0;i<1000000000;i++){
j++;
}
Never used it, but this exists
JCPP is a complete, compliant,
standalone, pure Java implementation
of the C preprocessor. It is intended
to be of use to people writing C-style
compilers in Java using tools like
sablecc, antlr, JLex, CUP and so
forth. This project has has been used
to successfully preprocess much of the
source code of the GNU C library. As
of version 1.2.5, it can also
preprocess the Apple Objective C
library.
http://www.anarres.org/projects/jcpp/
If you really need conditional compilation and you use Ant, you might be able to filter your code and do a search-and-replace in it.
For example: http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html
In the same manner you can, for example, write a filter to replace LOG.debug(...); with /*LOG.debug(...);*/. This would still execute faster than if (LOG.isDebugEnabled()) { ... } stuff, not to mention being more concise at the same time.
If you use Maven, there is a similar feature described here.
If you use IntelliJ there is a plugin called Manifold, that - along with many other features - allows one to use #ifdef and #define in Java.
Plugin url:
https://manifold.systems/
Preprocessor information:
https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-preprocessor
PS: I am not affiliated with them, we just happen to use it, and it helps a lot with out workflow (which is likely NOT typical for Java development)
Use the Factory Pattern to switch between implementations of a class?
The object creation time can't be a concern now could it? When averaged over a long running time period, the biggest component of time spent should be in the main algorithm now wouldn't it?
Strictly speaking, you don't really need a preprocessor to do what you seek to achieve. There are most probably other ways of meeting your requirement than the one I have proposed of course.
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0

Categories

Resources