Skip to content

Commit 1e17db6

Browse files
authored
Merge pull request #1735 from cesaro/core-models
JBMC Java Core models library
2 parents 6844760 + a8e659c commit 1e17db6

21 files changed

+385
-76
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ src/ansi-c/gcc_builtin_headers_tm.inc
4545
src/ansi-c/gcc_builtin_headers_mips.inc
4646
src/ansi-c/gcc_builtin_headers_power.inc
4747
src/ansi-c/gcc_builtin_headers_ubsan.inc
48+
src/java_bytecode/java_core_models.inc
4849

4950
# regression/test files
5051
*.out
@@ -115,6 +116,8 @@ src/ansi-c/file_converter
115116
src/ansi-c/file_converter.exe
116117
src/ansi-c/library/converter
117118
src/ansi-c/library/converter.exe
119+
src/java_bytecode/converter
120+
src/java_bytecode/converter.exe
118121
src/util/irep_ids_convert
119122
src/util/irep_ids_convert.exe
120123
build/
582 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
test.class
3+
--show-symbol-table
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Symbol\s*\.*\: java\:\:org\.cprover\.CProver\.\<clinit\>\:\(\)V$
7+
--
8+
--
9+
tests that the core models are being loaded by checking if the static initializer for the CProver class was
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import org.cprover.CProver;
2+
class test
3+
{
4+
public static void main(String[] args)
5+
{
6+
int i=CProver.nondetInt();
7+
assert(i!=0);
8+
}
9+
}
10+

regression/jbmc-strings/java_append_char/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
test_append_char.class
3-
--refine-strings --string-max-length 1000
3+
--refine-strings --string-max-length 1000 --no-core-models
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$

src/java_bytecode/CMakeLists.txt

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
file(GLOB_RECURSE sources "*.cpp" "*.h")
2-
add_library(java_bytecode ${sources})
1+
get_filename_component(JAVA_CORE_MODELS_INC "library/java_core_models.inc" REALPATH BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
2+
set_source_files_properties("library/java_core_models.inc" GENERATED)
3+
4+
file(GLOB sources "*.cpp")
5+
file(GLOB_RECURSE headers "*.h")
6+
add_subdirectory(library)
7+
8+
add_library(java_bytecode ${sources} ${headers} )
9+
add_dependencies(java_bytecode core_models_files)
10+
target_sources(java_bytecode PUBLIC ${sources} ${headers})
311

412
generic_includes(java_bytecode)
513

src/java_bytecode/Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ CLEANFILES = java_bytecode$(LIBEXT)
4040

4141
all: java_bytecode$(LIBEXT)
4242

43+
clean: clean_library
44+
45+
.PHONY: clean_library
46+
clean_library:
47+
$(MAKE) clean -C library
48+
49+
library/java_core_models.inc:
50+
$(MAKE) -C library java_core_models.inc
51+
52+
java_class_loader$(OBJEXT): library/java_core_models.inc
4353
###############################################################################
4454

4555
java_bytecode$(LIBEXT): $(OBJ)

src/java_bytecode/jar_file.cpp

+24-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ Author: Diffblue Ltd
1212
#include <util/invariant.h>
1313
#include "java_class_loader_limit.h"
1414

15-
jar_filet::jar_filet(
16-
java_class_loader_limitt &limit,
17-
const std::string &filename):
18-
m_zip_archive(filename)
15+
void jar_filet::initialize_file_index(java_class_loader_limitt &limit)
1916
{
2017
const size_t file_count=m_zip_archive.get_num_files();
2118
for(size_t index=0; index<file_count; index++)
@@ -26,6 +23,29 @@ jar_filet::jar_filet(
2623
}
2724
}
2825

26+
/// This constructor creates a jar_file object whose contents
27+
/// are extracted from a memory buffer (byte array) as opposed
28+
/// to a jar file.
29+
jar_filet::jar_filet(
30+
java_class_loader_limitt &limit,
31+
const std::string &filename):
32+
m_zip_archive(filename)
33+
{
34+
initialize_file_index(limit);
35+
}
36+
37+
/// This constructor creates a jar_file object whose contents
38+
/// are extracted from a memory buffer (byte array) as opposed
39+
/// to a jar file.
40+
jar_filet::jar_filet(
41+
java_class_loader_limitt &limit,
42+
const void *data,
43+
size_t size):
44+
m_zip_archive(data, size)
45+
{
46+
initialize_file_index(limit);
47+
}
48+
2949
// VS: No default move constructors or assigns
3050

3151
jar_filet::jar_filet(jar_filet &&other):

src/java_bytecode/jar_file.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,25 @@ class java_class_loader_limitt;
2121
class jar_filet final
2222
{
2323
public:
24-
/// Open java file for reading
24+
/// Open java file for reading.
2525
/// \param limit Object limiting number of loaded .class files
2626
/// \param filename Name of the file
2727
/// \throw Throws std::runtime_error if file cannot be opened
2828
jar_filet(java_class_loader_limitt &limit, const std::string &filename);
29+
30+
/// Open a JAR file of size \p size loaded in memory at address \p data.
31+
/// \param limit Object limiting number of loaded .class files
32+
/// \param data memory buffer with the contents of the jar file
33+
/// \param size size of the memory buffer
34+
/// \throw Throws std::runtime_error if file cannot be opened
35+
jar_filet(java_class_loader_limitt &limit, const void *data, size_t size);
36+
2937
jar_filet(const jar_filet &)=delete;
3038
jar_filet &operator=(const jar_filet &)=delete;
3139
jar_filet(jar_filet &&);
3240
jar_filet &operator=(jar_filet &&);
3341
~jar_filet()=default;
42+
3443
/// Get contents of a file in the jar archive.
3544
/// Terminates the program if file doesn't exist
3645
/// \param filename Name of the file in the archive
@@ -40,8 +49,12 @@ class jar_filet final
4049
/// Get list of filenames in the archive
4150
std::vector<std::string> filenames() const;
4251
private:
52+
/// Loads the fileindex (m_name_to_index) with a map of loaded files to
53+
/// indices.
54+
void initialize_file_index(java_class_loader_limitt &limit);
55+
4356
mz_zip_archivet m_zip_archive;
44-
/// Map of filename to the file index in the zip archive
57+
/// Map of filename to the file index in the zip archive.
4558
std::unordered_map<std::string, size_t> m_name_to_index;
4659
};
4760

src/java_bytecode/java_bytecode_language.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Author: Daniel Kroening, [email protected]
4242
void java_bytecode_languaget::get_language_options(const cmdlinet &cmd)
4343
{
4444
assume_inputs_non_null=cmd.isset("java-assume-inputs-non-null");
45+
java_class_loader.use_core_models=!cmd.isset("no-core-models");
4546
string_refinement_enabled=cmd.isset("refine-strings");
4647
throw_runtime_exceptions=cmd.isset("java-throw-runtime-exceptions");
4748
if(cmd.isset("java-max-input-array-length"))
@@ -267,6 +268,24 @@ bool java_bytecode_languaget::typecheck(
267268
if(string_refinement_enabled)
268269
string_preprocess.initialize_conversion_table();
269270

271+
// Must load java.lang.Object first to avoid stubbing
272+
// This ordering could alternatively be enforced by
273+
// moving the code below to the class loader.
274+
java_class_loadert::class_mapt::const_iterator it=
275+
java_class_loader.class_map.find("java.lang.Object");
276+
if(it!=java_class_loader.class_map.end())
277+
{
278+
if(java_bytecode_convert_class(
279+
it->second,
280+
symbol_table,
281+
get_message_handler(),
282+
max_user_array_length,
283+
method_bytecode,
284+
lazy_methods_mode,
285+
string_preprocess))
286+
return true;
287+
}
288+
270289
// first generate a new struct symbol for each class and a new function symbol
271290
// for every method
272291
for(java_class_loadert::class_mapt::const_iterator

src/java_bytecode/java_bytecode_language.h

+16-13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Author: Daniel Kroening, [email protected]
2424
#include <java_bytecode/select_pointer_type.h>
2525

2626
#define JAVA_BYTECODE_LANGUAGE_OPTIONS /*NOLINT*/ \
27+
"(no-core-models)" \
2728
"(java-assume-inputs-non-null)" \
2829
"(java-throw-runtime-exceptions)" \
2930
"(java-max-input-array-length):" \
@@ -35,19 +36,21 @@ Author: Daniel Kroening, [email protected]
3536
"(java-load-class):"
3637

3738
#define JAVA_BYTECODE_LANGUAGE_OPTIONS_HELP /*NOLINT*/ \
38-
" --java-assume-inputs-non-null never initialize reference-typed parameter to the\n" \
39-
" entry point with null\n" \
40-
" --java-throw-runtime-exceptions make implicit runtime exceptions explicit\n" \
41-
" --java-max-input-array-length N limit input array size to <= N\n" \
42-
" --java-max-input-tree-depth N object references are (deterministically) set to null in\n"\
43-
" the object\n" \
44-
" --java-max-vla-length limit the length of user-code-created arrays\n" \
45-
" --java-cp-include-files regexp or JSON list of files to load (with '@' prefix)\n" \
46-
" --lazy-methods only translate methods that appear to be reachable from\n" \
47-
" the --function entry point or main class\n" \
48-
" --lazy-methods-extra-entry-point METHODNAME\n" \
49-
" treat METHODNAME as a possible program entry point for\n" \
50-
" the purpose of lazy method loading\n" \
39+
" --no-core-models don't load internally provided models for core classes in\n"/* NOLINT(*) */ \
40+
" the Java Class Library\n" /* NOLINT(*) */ \
41+
" --java-assume-inputs-non-null never initialize reference-typed parameter to the\n" /* NOLINT(*) */ \
42+
" entry point with null\n" /* NOLINT(*) */ \
43+
" --java-throw-runtime-exceptions make implicit runtime exceptions explicit\n" /* NOLINT(*) */ \
44+
" --java-max-input-array-length N limit input array size to <= N\n" /* NOLINT(*) */ \
45+
" --java-max-input-tree-depth N object references are (deterministically) set to null in\n" /* NOLINT(*) */ \
46+
" the object\n" /* NOLINT(*) */ \
47+
" --java-max-vla-length limit the length of user-code-created arrays\n" /* NOLINT(*) */ \
48+
" --java-cp-include-files regexp or JSON list of files to load (with '@' prefix)\n" /* NOLINT(*) */ \
49+
" --lazy-methods only translate methods that appear to be reachable from\n" /* NOLINT(*) */ \
50+
" the --function entry point or main class\n" /* NOLINT(*) */ \
51+
" --lazy-methods-extra-entry-point METHODNAME\n" /* NOLINT(*) */ \
52+
" treat METHODNAME as a possible program entry point for\n" /* NOLINT(*) */ \
53+
" the purpose of lazy method loading\n" /* NOLINT(*) */ \
5154
" A '.*' wildcard is allowed to specify all class members\n"
5255

5356
#define MAX_NONDET_ARRAY_LENGTH_DEFAULT 5

0 commit comments

Comments
 (0)