(Unknown Source) in Exception stack trace
Background
This question is related to Why does String.valueOf(null) throw a NullPointerException?
Consider the following snippet:
As explained in the answer to the linked question, Java’s method overloading resolves the above invokation to String.valueOf(char[]) , which rightfully results in a NullPointerException at run-time.
Compiled in Eclipse and javac 1.6.0_17 , this is the stack trace:
Note that the stack trace above is missing the KEY information: it does NOT have the full signature of the valueOf method! It just says String.valueOf(Unknown Source) !
In most situations I’ve encountered, exception stack traces always have the complete signature of the methods that are actually in the stack trace, which of course is very helpful in identifying the problem immediately and a major reason why the stack trace (which needless to say is rather expensive to construct) is provided in the first place.
And yet, in this case, the stack trace does not help at all. It has failed miserably in helping the programmer identify the problem.
As is, I can see 3 ways that a programmer can identify the problem with the above snippet:
- Programmer realizes on his/her own that the method is overloaded, and by resolution rule, the «wrong» overload gets invoked in this case
- Programmer uses a good IDE that allows him/her to quickly see which method is selected
- In Eclipse, for example, mouse-hovering on the above expression quickly tells programmer that the String valueOf(char[] data) is indeed the one selected
- Programmer examines the bytecode (ugh!)
The last option is probably the least accessible, but of course is the Ultimate Answer (a programmer may misunderstood the overloading rule, IDE may be buggy, but bytecodes always(?) tell the truth on what’s being done).
The questions
- Why is the stack trace so uninformative in this case with regards to the signatures of the methods that are actually in the stack trace?
- Is this due to the compiler? The runtime? Something else?
- In what other (rare?) scenarios can the stack trace fail to capture essential information like these?
Answers
This is normally related to missing debug information. You are probably using JRE (not JDK), which does not include debug information for rt.jar classes. Try using full JDK, you’ll get proper locations in the stack trace:
Throwable.printStackTrace() writes the stack trace to System.err PrintStream. The System.err stream and the underlying standard «error» output stream of the JVM process can be redirected by
- invoking System.setErr() which changes the destination pointed to by System.err .
- or by redirecting the process’ error output stream. The error output stream may be redirected to a file/device
- whose contents may be ignored by personnel,
- the file/device may not be capable of log rotation, inferring that a process restart is required to close the open file/device handle, before archiving the existing contents of the file/device.
- or the file/device actually discards all data written to it, as is the case of /dev/null .
Inferring from the above, invoking Throwable.printStackTrace() constitutes valid (not good/great) exception handling behavior, only
- if you do not have System.err being reassigned throughout the duration of the application’s lifetime,
- and if you do not require log rotation while the application is running,
- and if accepted/designed logging practice of the application is to write to System.err (and the JVM’s standard error output stream).
In most cases, the above conditions are not satisfied. One may not be aware of other code running in the JVM, and one cannot predict the size of the log file or the runtime duration of the process, and a well designed logging practice would revolve around writing «machine-parseable» log files (a preferable but optional feature in a logger) in a known destination, to aid in support.
Источник
How to Get meaningful stack trace in Android #984
Comments
Tan2NT commented Jul 18, 2018 •
I have built my project with Asan, compile with -fsanitize=address -fno-omit-frame-pointer -O1
But the log does not show the file and function where the crash occur.
I see this guide how to get stack trace for asan: https://github.com/google/sanitizers/wiki/AddressSanitizerCallStack
Is this link is for Android too?
What detail should i do?
Below is the log cat of crash:
07-18 20:33:00.952: I/(13918): ==13918==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x49933954 at pc 0xa4dcb5b4 bp 0x9e9ff018 sp 0x9e9ff010
07-18 20:33:00.952: I/(13918): READ of size 4 at 0x49933954 thread T324 (Thread-379)
07-18 20:33:00.962: W/System.err(13918): remove failed: ENOENT (No such file or directory) : package.myapp/shared_prefs/com.google.android.gms.appid.xml.bak
07-18 20:33:00.987: I/(13918): #0 0xa4dcb5b3 (/data/app/package-1/lib/arm/libGame.so+0x10245b3)
07-18 20:33:00.992: I/(13918): #1 0xa4dcbbe7 (/package/lib/arm/libGame.so+0x1024be7)
07-18 20:33:00.992: I/(13918): #2 0xa4dd33d7 (/package/lib/arm/libGame.so+0x102c3d7)
07-18 20:33:00.992: I/(13918): #3 0xa51207a3 (/package/lib/arm/libGame.so+0x13797a3)
07-18 20:33:00.992: I/(13918): #4 0xa4d670b7 (/package/lib/arm/libGame.so+0xfc00b7)
07-18 20:33:00.992: I/(13918): #5 0xac18d617 (/package/lib/arm/libGame.so+0x83e6617)
07-18 20:33:00.992: I/(13918): #6 0xac18ca77 (/package/lib/arm/libGame.so+0x83e5a77)
07-18 20:33:00.992: I/(13918): #7 0xb6784e3b (/system/lib/libc.so+0x3fe3b)
07-18 20:33:00.992: I/(13918): #8 0xb675f55b (/system/lib/libc.so+0x1a55b)
07-18 20:33:00.997: D/TimaKeyStoreProvider(14724): TimaSignature is unavailable
07-18 20:33:00.997: D/ActivityThread(14724): Added TimaKeyStore provider
07-18 20:33:01.007: I/(13918): 0x49933954 is located 0 bytes to the right of 4-byte region [0x49933950,0x49933954)
07-18 20:33:01.007: I/(13918): allocated by thread T324 (Thread-379) here:
07-18 20:33:01.007: I/(13918): #0 0xb6a55077 (/system/lib/libclang_rt.asan-arm-android.so+0x82077)
07-18 20:33:01.007: I/(13918): Thread T324 (Thread-379) created by T0 (.ANMP.myapp) here:
07-18 20:33:01.007: I/(13918): #0 0xb6a2f4db (/system/lib/libclang_rt.asan-arm-android.so+0x5c4db)
07-18 20:33:01.007: I/(13918): #1 0xaeb36d3d (/package/oat/arm/base.odex+0xc34d3d)
07-18 20:33:01.012: I/(13918): SUMMARY: AddressSanitizer: heap-buffer-overflow (/package/lib/arm/libGame.so+0x10245b3)
07-18 20:33:01.012: I/(13918): Shadow bytes around the buggy address:
07-18 20:33:01.012: I/(13918): 0x093266d0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
07-18 20:33:01.012: I/(13918): 0x093266e0: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
07-18 20:33:01.012: I/(13918): 0x093266f0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 00 04
07-18 20:33:01.012: I/(13918): 0x09326700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
07-18 20:33:01.012: I/(13918): 0x09326710: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
07-18 20:33:01.012: I/(13918): =>0x09326720: fa fa fa fa fa fa fa fa fa fa[04]fa fa fa fd fd
07-18 20:33:01.012: I/(13918): 0x09326730: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
07-18 20:33:01.012: I/(13918): 0x09326740: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd
07-18 20:33:01.012: I/(13918): 0x09326750: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
07-18 20:33:01.012: I/(13918): 0x09326760: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
07-18 20:33:01.012: I/(13918): 0x09326770: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 00 04
07-18 20:33:01.012: I/(13918): Shadow byte legend (one shadow byte represents 8 application bytes):
07-18 20:33:01.012: I/(13918): Addressable: 00
07-18 20:33:01.012: I/(13918): Partially addressable: 01 02 03 04 05 06 07
07-18 20:33:01.012: I/(13918): Heap left redzone: fa
07-18 20:33:01.012: I/(13918): Heap right redzone: fb
07-18 20:33:01.012: I/(13918): Freed heap region: fd
07-18 20:33:01.012: I/(13918): Stack left redzone: f1
07-18 20:33:01.012: I/(13918): Stack mid redzone: f2
07-18 20:33:01.012: I/(13918): Stack right redzone: f3
07-18 20:33:01.012: I/(13918): Stack partial redzone: f4
07-18 20:33:01.012: I/(13918): Stack after return: f5
07-18 20:33:01.012: I/(13918): Stack use after scope: f8
07-18 20:33:01.012: I/(13918): Global redzone: f9
07-18 20:33:01.012: I/(13918): Global init order: f6
07-18 20:33:01.012: I/(13918): Poisoned by user: f7
07-18 20:33:01.012: I/(13918): Container overflow: fc
07-18 20:33:01.012: I/(13918): Array cookie: ac
07-18 20:33:01.012: I/(13918): Intra object redzone: bb
07-18 20:33:01.012: I/(13918): ASan internal: fe
07-18 20:33:01.012: I/(13918): Left alloca redzone: ca
07-18 20:33:01.012: I/(13918): Right alloca redzone: cb
07-18 20:33:01.012: I/(13918): ==13918==ABORTING
The text was updated successfully, but these errors were encountered:
Источник
Что такое трассировка стека и как я могу использовать ее для устранения ошибок приложения?
Иногда, когда я запускаю свое приложение, оно выдает мне ошибку, которая выглядит следующим образом:
Люди называют это «следом стека». Что такое трассировка стека? Что он может сказать мне об ошибке, которая происходит в моей программе?
Об этом вопросе — довольно часто я вижу вопрос, когда начинающий программист «получает ошибку», и они просто вставляют свою трассировку стека и некоторый случайный блок кода, не понимая, что такое трассировка стека или как они могут ее использовать. Этот вопрос предназначен для начинающих программистов, которым может понадобиться помощь в понимании значения трассировки стека.
Проще говоря, трассировка стека — это список вызовов методов, которые приложение находилось в середине, когда было сгенерировано исключение.
Простой пример
С помощью примера, приведенного в вопросе, мы можем точно определить, где было выброшено исключение в приложении. Давайте посмотрим на трассировку стека:
Это очень простая трассировка стека. Если мы начнем с начала списка «at . », мы можем сказать, где произошла наша ошибка. Мы ищем самый верхний вызов метода, который является частью нашего приложения. В данном случае это:
Чтобы отладить это, мы можем открыть Book.java и посмотреть на строку 16 , которая:
Это будет означать, что что-то (вероятно title ) находится null в приведенном выше коде.
Пример с цепочкой исключений
Иногда приложения перехватывают исключение и повторно генерируют его как причину другого исключения. Это обычно выглядит так:
Это может дать вам трассировку стека, которая выглядит следующим образом:
То, что отличается от этого, это «Причины». Иногда исключения будут иметь несколько разделов «Причины». Для них обычно требуется найти «основную причину», которая будет одной из самых низких «причинных» секций в трассировке стека. В нашем случае это:
Опять же , с этим исключением мы хотели бы посмотреть на линию 22 из , Book.java чтобы увидеть , что может привести NullPointerException здесь.
Более сложный пример с библиотечным кодом
Обычно трассировки стека намного сложнее, чем два приведенных выше примера. Вот пример (он длинный, но демонстрирует несколько уровней связанных исключений):
В этом примере намного больше. Что нас больше всего беспокоит, так это поиск методов, взятых из нашего кода , которые будут в com.example.myproject пакете. Из второго примера (выше), мы сначала хотели бы найти первопричину, а именно:
Однако все вызовы методов в соответствии с этим являются библиотечным кодом. Итак, мы перейдем к «Причины» над ним и поищем первый вызов метода, происходящий из нашего кода, а именно:
Как и в предыдущих примерах, мы должны смотреть MyEntityService.java онлайн 59 , потому что именно здесь возникла эта ошибка (эта ошибка немного очевидна, что пошло не так, поскольку SQLException сообщает об ошибке, но мы ищем процедуру отладки).
Я публикую этот ответ, поэтому самый верхний ответ (при сортировке по активности) не является просто ошибочным.
Что такое Stacktrace?
Stacktrace — очень полезный инструмент отладки. Он показывает стек вызовов (т. Е. Стек функций, которые были вызваны до этой точки) в момент возникновения неперехваченного исключения (или в момент, когда трассировка стека была сгенерирована вручную). Это очень полезно, поскольку показывает не только, где произошла ошибка, но и то, как программа оказалась в этом месте кода. Это приводит к следующему вопросу:
Что такое исключение?
Исключением является то, что среда выполнения использует, чтобы сообщить вам, что произошла ошибка. Популярные примеры: NullPointerException, IndexOutOfBoundsException или ArithmeticException. Каждый из них вызывается, когда вы пытаетесь сделать что-то, что невозможно. Например, исключение NullPointerException будет выдано при попытке разыменования объекта Null:
Как я должен иметь дело со стеками / исключениями?
Сначала выясните, что вызывает исключение. Попробуйте поискать название исключения, чтобы выяснить причину этого исключения. В большинстве случаев это будет вызвано неправильным кодом. В приведенных выше примерах все исключения вызваны неправильным кодом. Так что для примера NullPointerException вы можете убедиться, что a он никогда не будет нулевым в то время. Вы можете, например, инициализировать a или включить проверку, подобную этой:
Таким образом, оскорбительная строка не выполняется, если a==null . То же самое касается других примеров.
Иногда вы не можете быть уверены, что не получите исключения. Например, если вы используете сетевое соединение в своей программе, вы не можете остановить компьютер от потери его интернет-соединения (например, вы не можете запретить пользователю отключать сетевое соединение компьютера). В этом случае сетевая библиотека, вероятно, выдаст исключение. Теперь вы должны поймать исключение и обработать его. Это означает, что в примере с сетевым подключением вы должны попытаться повторно открыть подключение или уведомить пользователя или что-то в этом роде. Кроме того, всякий раз, когда вы используете catch, всегда перехватываете только исключение, которое вы хотите перехватить, не используйте такие широкие операторы catch, как catch (Exception e) что бы поймать все исключения. Это очень важно, потому что в противном случае вы можете случайно поймать не то исключение и отреагировать неправильно.
Почему я не должен использовать catch (Exception e) ?
Давайте используем небольшой пример, чтобы показать, почему вы не должны просто перехватывать все исключения:
Этот код пытается отловить ArithmeticException причину, вызванную возможным делением, на 0. Но он также отлавливает возможное NullPointerException , которое выбрасывается, если a или b есть null . Это означает, что вы можете получить, NullPointerException но вы будете относиться к нему как к ArithmeticException и, вероятно, будете поступать неправильно. В лучшем случае вы все еще скучаете по тому, что было исключение NullPointerException. Такие вещи делают отладку намного сложнее, так что не делайте этого.
TLDR
- Выясните причину исключения и устраните его, чтобы исключение вообще не генерировалось.
Если 1. невозможно, перехватите конкретное исключение и обработайте его.
- Никогда не добавляйте try / catch, а затем просто игнорируйте исключение! Не делай этого!
- Никогда не используйте catch (Exception e) , всегда ловите определенные исключения. Это избавит вас от многих головных болей.
Источник