Skip to content

Commit bcde700

Browse files
Merge pull request #5199 from peterschrammel/jbmc-accept-method-name
JBMC accepts method name directly
2 parents 5e95689 + 8c6ea70 commit bcde700

23 files changed

+149
-9
lines changed

doc/cprover-manual/jbmc-user-manual.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ depends on an input):
123123
To limit the number of times the for-loop is unwound, we use the `--unwind N`
124124
options, in which case the following call to JBMC:
125125
```
126-
$ jbmc tutorial.ExampleUnwind --function tutorial.ExampleUnwind.isPrime --unwind 10
126+
$ jbmc tutorial.ExampleUnwind.isPrime --unwind 10
127127
```
128128
will terminate correctly. In this case, we will see `VERIFICATION SUCCESSFUL`,
129129
as no automatic assertions are violated.
@@ -139,7 +139,7 @@ JBMC will try to refute. On line 7, we check the assertion that all odd
139139
numbers greater than 1 are prime. To be sure that this always holds, we run
140140
JBMC on the example, with a reasonable `unwind` value:
141141
```
142-
$ jbmc tutorial.ExampleUnwind --function tutorial.ExampleUnwind.doSomething --unwind 10
142+
$ jbmc tutorial.ExampleUnwind.doSomething --unwind 10
143143
```
144144
Unsurprisingly JBMC doesn't agree, and prints an assertion failure
145145
(truncated here for readability):
@@ -223,7 +223,7 @@ Consider the following code:
223223

224224
When given the `--throw-runtime-exceptions` options:
225225
```
226-
$ jbmc tutorial.ExampleExceptions --tutorial.ExampleExceptions.strLength --throw-runtime-exceptions
226+
$ jbmc tutorial.ExampleExceptions.strLength --throw-runtime-exceptions
227227
```
228228
JBMC will signal that the `str.length()` call may throw a runtime exception
229229
and that this exception is not caught.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
public class NoPackage {
2+
public static class Nested {
3+
public static class Deeper {
4+
}
5+
}
6+
}
Binary file not shown.
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package mypackage;
2+
3+
public class Package {
4+
public static class Inner {
5+
}
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
'mypackage.Package$Inner.<init>'
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Found Java main class: mypackage.Package\$Inner$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
'NoPackage$Nested$Deeper.<init>'
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Found Java main class: NoPackage\$Nested\$Deeper$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
'NoPackage.<init>:()V'
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Found Java main class: NoPackage$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
'mypackage.Package.<init>'
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Found Java main class: mypackage.Package$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
'mypackage.Baggage'
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^Error: Could not find or load main class mypackage\.Baggage$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
3+
mypackage.Baggage.do
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^Error: Could not find or load main class mypackage\.Baggage\.do$
7+
--
8+
--
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
3+
'mypackage.Package.do:()V'
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
^Found Java main class: mypackage.Package$
7+
^main symbol resolution failed: 'mypackage.Package.do:\(\)V' not found$
8+
--
9+
--

jbmc/src/janalyzer/janalyzer_parse_options.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,8 @@ void janalyzer_parse_optionst::help()
751751
"\n"
752752
" janalyzer [-?] [-h] [--help] show help\n"
753753
" janalyzer\n"
754+
HELP_JAVA_METHOD_NAME
755+
" janalyzer\n"
754756
HELP_JAVA_CLASS_NAME
755757
" janalyzer\n"
756758
HELP_JAVA_JAR

jbmc/src/java_bytecode/java_bytecode_language.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,16 +318,46 @@ void java_bytecode_languaget::initialize_class_loader()
318318
}
319319
}
320320

321+
static void throwMainClassLoadingError(const std::string &main_class)
322+
{
323+
throw invalid_source_file_exceptiont(
324+
"Error: Could not find or load main class " + main_class);
325+
}
326+
321327
void java_bytecode_languaget::parse_from_main_class()
322328
{
323329
if(!main_class.empty())
324330
{
325-
status() << "Java main class: " << main_class << eom;
331+
// Try to load class
332+
status() << "Trying to load Java main class: " << main_class << eom;
333+
if(!java_class_loader.can_load_class(main_class))
334+
{
335+
// Try to extract class name and load class
336+
const auto maybe_class_name =
337+
class_name_from_method_name(id2string(main_class));
338+
if(!maybe_class_name)
339+
{
340+
throwMainClassLoadingError(id2string(main_class));
341+
return;
342+
}
343+
status() << "Trying to load Java main class: " << maybe_class_name.value()
344+
<< eom;
345+
if(!java_class_loader.can_load_class(maybe_class_name.value()))
346+
{
347+
throwMainClassLoadingError(id2string(main_class));
348+
return;
349+
}
350+
// Everything went well. We have a loadable main class.
351+
// The entry point ('main') will be checked later.
352+
config.main = id2string(main_class);
353+
main_class = maybe_class_name.value();
354+
}
355+
status() << "Found Java main class: " << main_class << eom;
356+
// Now really load it.
326357
const auto &parse_trees = java_class_loader(main_class);
327358
if(parse_trees.empty() || !parse_trees.front().loading_successful)
328359
{
329-
throw invalid_source_file_exceptiont(
330-
"Error: Could not find or load main class " + id2string(main_class));
360+
throwMainClassLoadingError(id2string(main_class));
331361
}
332362
}
333363
}

jbmc/src/java_bytecode/java_bytecode_language.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,17 @@ Author: Daniel Kroening, [email protected]
140140
" jar files\n" \
141141
" A " JAVA_CLASSPATH_SEPARATOR \
142142
" separated list of directories and JAR\n" \
143-
" archives to search for class files.\n" \
143+
" archives to search for class files.\n" \
144144
" --main-class class-name set the name of the main class\n"
145145

146+
#define HELP_JAVA_METHOD_NAME /* NOLINT(*) */ \
147+
" method-name fully qualified name of method\n" \
148+
" used as entry point, e.g.\n" \
149+
" mypackage.Myclass.foo:(I)Z\n"
150+
146151
#define HELP_JAVA_CLASS_NAME /* NOLINT(*) */ \
147152
" class-name name of class\n" \
148-
" The entry point is the method specified by\n" /* NOLINT(*) */ \
153+
" The entry point is the method specified by\n" \
149154
" --function, or otherwise, the\n" \
150155
" public static void main(String[])\n" \
151156
" method of the given class.\n"
@@ -154,7 +159,7 @@ Author: Daniel Kroening, [email protected]
154159
"(jar):"
155160

156161
#define HELP_JAVA_JAR /* NOLINT(*) */ \
157-
" -jar jarfile JAR file to be checked\n" \
162+
" -jar jarfile JAR file to be checked\n" \
158163
" The entry point is the method specified by\n" \
159164
" --function or otherwise, the\n" \
160165
" public static void main(String[]) method\n" \

jbmc/src/java_bytecode/java_class_loader.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,17 @@ static bool is_overlay_class(const java_bytecode_parse_treet::classt &c)
103103
.has_value();
104104
}
105105

106+
bool java_class_loadert::can_load_class(const irep_idt &class_name)
107+
{
108+
for(const auto &cp_entry : classpath_entries)
109+
{
110+
auto parse_tree = load_class(class_name, cp_entry);
111+
if(parse_tree.has_value())
112+
return true;
113+
}
114+
return false;
115+
}
116+
106117
/// Check through all the places class parse trees can appear and returns the
107118
/// first implementation it finds plus any overlay class implementations.
108119
/// Uses \p class_loader_limit to limit the class files that it might (directly

jbmc/src/java_bytecode/java_class_loader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class java_class_loadert : public java_class_loader_baset
4343

4444
parse_tree_with_overlayst &operator()(const irep_idt &class_name);
4545

46+
/// Checks whether \p class_name is parseable from the classpath,
47+
/// ignoring class loading limits.
48+
bool can_load_class(const irep_idt &class_name);
49+
4650
parse_tree_with_overlayst &get_parse_tree(
4751
java_class_loader_limitt &class_loader_limit,
4852
const irep_idt &class_name);

jbmc/src/java_bytecode/java_utils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,13 @@ void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class)
507507
{
508508
symbol.type.set(ID_C_class, declaring_class);
509509
}
510+
511+
NODISCARD optionalt<std::string>
512+
class_name_from_method_name(const std::string &method_name)
513+
{
514+
const auto signature_index = method_name.rfind(":");
515+
const auto method_index = method_name.rfind(".", signature_index);
516+
if(method_index == std::string::npos)
517+
return {};
518+
return method_name.substr(0, method_index);
519+
}

jbmc/src/java_bytecode/java_utils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414
#include <unordered_set>
1515

1616
#include <util/message.h>
17+
#include <util/nodiscard.h>
1718
#include <util/optional.h>
1819
#include <util/std_expr.h>
1920
#include <util/symbol_table.h>
@@ -145,4 +146,10 @@ optionalt<irep_idt> declaring_class(const symbolt &symbol);
145146
/// declaring_class.
146147
void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class);
147148

149+
/// Get JVM type name of the class in which \p method_name is defined.
150+
/// Returns an empty optional if the class name cannot be retrieved,
151+
/// e.g. method_name is an internal function.
152+
NODISCARD optionalt<std::string>
153+
class_name_from_method_name(const std::string &method_name);
154+
148155
#endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,8 @@ void jbmc_parse_optionst::help()
10511051
"\n"
10521052
" jbmc [-?] [-h] [--help] show help\n"
10531053
" jbmc\n"
1054+
HELP_JAVA_METHOD_NAME
1055+
" jbmc\n"
10541056
HELP_JAVA_CLASS_NAME
10551057
" jbmc\n"
10561058
HELP_JAVA_JAR

0 commit comments

Comments
 (0)