Skip to content

Commit b047091

Browse files
Simplify main method detection for Java
1 parent b726dd1 commit b047091

File tree

1 file changed

+36
-42
lines changed

1 file changed

+36
-42
lines changed

jbmc/src/java_bytecode/java_entry_point.cpp

+36-42
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Author: Daniel Kroening, [email protected]
2222
#include "java_string_literals.h"
2323
#include "java_utils.h"
2424

25+
#define JAVA_MAIN_METHOD "main:([Ljava/lang/String;)V"
26+
2527
static void create_initialize(symbol_table_baset &symbol_table)
2628
{
2729
// If __CPROVER_initialize already exists, replace it. It may already exist
@@ -242,6 +244,27 @@ static void java_static_lifetime_init(
242244
}
243245
}
244246

247+
/// Checks whether the given symbol is a valid java main method
248+
/// i.e. it must be public, static, called 'main' and
249+
/// have signature void(String[])
250+
/// \param function: the function symbol
251+
/// \return true if it is a valid main method
252+
bool is_java_main(const symbolt &function)
253+
{
254+
bool named_main = has_suffix(id2string(function.name), JAVA_MAIN_METHOD);
255+
const code_typet &function_type = to_code_type(function.type);
256+
const typet &string_array_type = java_type_from_string("[Ljava/lang/String;");
257+
// checks whether the function is static and has a single String[] parameter
258+
bool is_static = !function_type.has_this();
259+
// this should be implied by the signature
260+
const code_typet::parameterst &parameters = function_type.parameters();
261+
bool has_correct_type = function_type.return_type().id() == ID_empty &&
262+
parameters.size() == 1 &&
263+
parameters[0].type().full_eq(string_array_type);
264+
bool public_access = function_type.get(ID_access) == ID_public;
265+
return named_main && is_static && has_correct_type && public_access;
266+
}
267+
245268
/// Extends \p init_code with code that allocates the objects used as test
246269
/// arguments for the function under test (\p function) and
247270
/// non-deterministically initializes them.
@@ -268,24 +291,7 @@ exprt::operandst java_build_arguments(
268291
// certain method arguments cannot be allowed to be null, we set the following
269292
// variable to true iff the method under test is the "main" method, which will
270293
// be called (by the jvm) with arguments that are never null
271-
bool is_default_entry_point(config.main.empty());
272-
bool is_main=is_default_entry_point;
273-
274-
// if walks like a duck and quacks like a duck, it is a duck!
275-
if(!is_main)
276-
{
277-
bool named_main=has_suffix(config.main, ".main");
278-
const typet &string_array_type=
279-
java_type_from_string("[Ljava.lang.String;");
280-
// checks whether the function is static and has a single String[] parameter
281-
bool has_correct_type=
282-
to_code_type(function.type).return_type().id()==ID_empty &&
283-
(!to_code_type(function.type).has_this()) &&
284-
parameters.size()==1 &&
285-
parameters[0].type().full_eq(string_array_type);
286-
bool public_access = function.type.get(ID_access) == ID_public;
287-
is_main = named_main && has_correct_type && public_access;
288-
}
294+
bool is_main = is_java_main(function);
289295

290296
// we iterate through all the parameters of the function under test, allocate
291297
// an object for that parameter (recursively allocating other objects
@@ -455,37 +461,25 @@ main_function_resultt get_main_symbol(
455461

456462
// are we given a main class?
457463
if(main_class.empty())
458-
return main_function_resultt::NotFound; // silently ignore
459-
460-
std::string entry_method = id2string(main_class) + ".main";
461-
462-
std::string prefix="java::"+entry_method+":";
463-
464-
// look it up
465-
std::set<const symbolt *> matches;
466-
467-
for(const auto &named_symbol : symbol_table.symbols)
468464
{
469-
if(named_symbol.second.type.id() == ID_code
470-
&& has_prefix(id2string(named_symbol.first), prefix))
471-
{
472-
matches.insert(&named_symbol.second);
473-
}
465+
// no, but we allow this situation to output symbol table,
466+
// goto functions, etc
467+
return main_function_resultt::NotFound;
474468
}
475469

476-
if(matches.empty())
477-
// Not found, silently ignore
478-
return main_function_resultt::NotFound;
470+
std::string entry_method =
471+
"java::" + id2string(main_class) + "." + JAVA_MAIN_METHOD;
472+
const symbolt *symbol = symbol_table.lookup(entry_method);
479473

480-
if(matches.size() > 1)
474+
// has the class a correct main method?
475+
if(!symbol || !is_java_main(*symbol))
481476
{
482-
message.error()
483-
<< "main method in `" << main_class
484-
<< "' is ambiguous" << messaget::eom;
485-
return main_function_resultt::Error; // give up with error, no main
477+
// no, but we allow this situation to output symbol table,
478+
// goto functions, etc
479+
return main_function_resultt::NotFound;
486480
}
487481

488-
return **matches.begin(); // Return found function
482+
return *symbol;
489483
}
490484
}
491485

0 commit comments

Comments
 (0)