Move through a list of stack frames, searching for references to code found in the current sketch. Return with a RunnerException that contains the location of the error, or if nothing is found, just return with a RunnerException that wraps the error message itself.
(String message, ObjectReference or, ThreadReference thread)
| 806 | * RunnerException that wraps the error message itself. |
| 807 | */ |
| 808 | protected SketchException findException(String message, ObjectReference or, ThreadReference thread) { |
| 809 | try { |
| 810 | // use to dump the stack for debugging |
| 811 | // for (StackFrame frame : thread.frames()) { |
| 812 | // System.out.println("frame: " + frame); |
| 813 | // } |
| 814 | |
| 815 | List<StackFrame> frames = thread.frames(); |
| 816 | for (StackFrame frame : frames) { |
| 817 | try { |
| 818 | Location location = frame.location(); |
| 819 | String filename = location.sourceName(); |
| 820 | int lineNumber = location.lineNumber() - 1; |
| 821 | SketchException rex = |
| 822 | build.placeException(message, filename, lineNumber); |
| 823 | if (rex != null) { |
| 824 | return rex; |
| 825 | } |
| 826 | } catch (AbsentInformationException e) { |
| 827 | // Any of the thread.blah() methods can throw an AbsentInformationEx |
| 828 | // if that bit of data is missing. If so, just write out the error |
| 829 | // message to the console. |
| 830 | //e.printStackTrace(); // not useful |
| 831 | exception = new SketchException(message); |
| 832 | exception.hideStackTrace(); |
| 833 | listener.statusError(exception); |
| 834 | } |
| 835 | } |
| 836 | } catch (IncompatibleThreadStateException e) { |
| 837 | // This shouldn't happen, but if it does, print the exception in case |
| 838 | // it's something that needs to be debugged separately. |
| 839 | e.printStackTrace(sketchErr); |
| 840 | } catch (Exception e) { |
| 841 | // stack overflows seem to trip in frame.location() above |
| 842 | // ignore this case so that the actual error gets reported to the user |
| 843 | if (!"StackOverflowError".equals(message)) { |
| 844 | e.printStackTrace(sketchErr); |
| 845 | } |
| 846 | } |
| 847 | // before giving up, try to extract from the throwable object itself |
| 848 | // since sometimes exceptions are re-thrown from a different context |
| 849 | try { |
| 850 | // assume object reference is Throwable, get stack trace |
| 851 | Method method = ((ClassType) or.referenceType()).concreteMethodByName("getStackTrace", "()[Ljava/lang/StackTraceElement;"); |
| 852 | ArrayReference result = (ArrayReference) or.invokeMethod(thread, method, new ArrayList<>(), ObjectReference.INVOKE_SINGLE_THREADED); |
| 853 | // iterate through stack frames and pull filename and line number for each |
| 854 | for (Value val: result.getValues()) { |
| 855 | ObjectReference ref = (ObjectReference)val; |
| 856 | method = ((ClassType) ref.referenceType()).concreteMethodByName("getFileName", "()Ljava/lang/String;"); |
| 857 | StringReference strref = (StringReference) ref.invokeMethod(thread, method, new ArrayList<>(), ObjectReference.INVOKE_SINGLE_THREADED); |
| 858 | String filename = strref == null ? "Unknown Source" : strref.value(); |
| 859 | method = ((ClassType) ref.referenceType()).concreteMethodByName("getLineNumber", "()I"); |
| 860 | IntegerValue intval = (IntegerValue) ref.invokeMethod(thread, method, new ArrayList<>(), ObjectReference.INVOKE_SINGLE_THREADED); |
| 861 | int lineNumber = intval.intValue() - 1; |
| 862 | SketchException rex = |
| 863 | build.placeException(message, filename, lineNumber); |
| 864 | if (rex != null) { |
| 865 | return rex; |
no test coverage detected