64 #include "runtime/mutexLocker.hpp"
65 #include "runtime/os.hpp"
66 #include "runtime/vm_version.hpp"
67 #include "utilities/align.hpp"
68 #include "utilities/bitMap.inline.hpp"
69 #include "utilities/classpathStream.hpp"
70 #include "utilities/defaultStream.hpp"
71 #include "utilities/ostream.hpp"
72 #if INCLUDE_G1GC
73 #include "gc/g1/g1CollectedHeap.hpp"
74 #include "gc/g1/g1HeapRegion.hpp"
75 #endif
76
77 # include <sys/stat.h>
78 # include <errno.h>
79
80 #ifndef O_BINARY // if defined (Win32) use binary files.
81 #define O_BINARY 0 // otherwise do nothing.
82 #endif
83
84 // Fill in the fileMapInfo structure with data about this VM instance.
85
86 // This method copies the vm version info into header_version. If the version is too
87 // long then a truncated version, which has a hash code appended to it, is copied.
88 //
89 // Using a template enables this method to verify that header_version is an array of
90 // length JVM_IDENT_MAX. This ensures that the code that writes to the CDS file and
91 // the code that reads the CDS file will both use the same size buffer. Hence, will
92 // use identical truncation. This is necessary for matching of truncated versions.
93 template <int N> static void get_header_version(char (&header_version) [N]) {
94 assert(N == JVM_IDENT_MAX, "Bad header_version size");
95
96 const char *vm_version = VM_Version::internal_vm_info_string();
97 const int version_len = (int)strlen(vm_version);
98
99 memset(header_version, 0, JVM_IDENT_MAX);
100
101 if (version_len < (JVM_IDENT_MAX-1)) {
102 strcpy(header_version, vm_version);
103
198 set_version(CURRENT_CDS_ARCHIVE_VERSION);
199
200 if (!info->is_static() && base_archive_name_size != 0) {
201 // copy base archive name
202 copy_base_archive_name(CDSConfig::static_archive_path());
203 }
204 _core_region_alignment = core_region_alignment;
205 _obj_alignment = ObjectAlignmentInBytes;
206 _compact_strings = CompactStrings;
207 if (CDSConfig::is_dumping_heap()) {
208 _narrow_oop_mode = CompressedOops::mode();
209 _narrow_oop_base = CompressedOops::base();
210 _narrow_oop_shift = CompressedOops::shift();
211 }
212 _compressed_oops = UseCompressedOops;
213 _compressed_class_ptrs = UseCompressedClassPointers;
214 _use_secondary_supers_table = UseSecondarySupersTable;
215 _max_heap_size = MaxHeapSize;
216 _use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
217 _has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
218
219 // The following fields are for sanity checks for whether this archive
220 // will function correctly with this JVM and the bootclasspath it's
221 // invoked with.
222
223 // JVM version string ... changes on each build.
224 get_header_version(_jvm_ident);
225
226 _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
227 _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
228 _max_used_path_index = ClassLoaderExt::max_used_path_index();
229 _num_module_paths = ClassLoader::num_module_path_entries();
230
231 _verify_local = BytecodeVerificationLocal;
232 _verify_remote = BytecodeVerificationRemote;
233 _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
234 _has_non_jar_in_classpath = ClassLoaderExt::has_non_jar_in_classpath();
235 _requested_base_address = (char*)SharedBaseAddress;
236 _mapped_base_address = (char*)SharedBaseAddress;
237 _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
238
239 if (!CDSConfig::is_dumping_dynamic_archive()) {
240 set_shared_path_table(info->_shared_path_table);
241 }
242 }
243
244 void FileMapHeader::copy_base_archive_name(const char* archive) {
245 assert(base_archive_name_size() != 0, "_base_archive_name_size not set");
246 assert(base_archive_name_offset() != 0, "_base_archive_name_offset not set");
247 assert(header_size() > sizeof(*this), "_base_archive_name_size not included in header size?");
248 memcpy((char*)this + base_archive_name_offset(), archive, base_archive_name_size());
249 }
250
251 void FileMapHeader::print(outputStream* st) {
252 ResourceMark rm;
253
254 st->print_cr("- magic: 0x%08x", magic());
255 st->print_cr("- crc: 0x%08x", crc());
256 st->print_cr("- version: 0x%x", version());
257 st->print_cr("- header_size: " UINT32_FORMAT, header_size());
280 st->print_cr("- jvm_ident: %s", _jvm_ident);
281 st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset);
282 st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index);
283 st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index);
284 st->print_cr("- num_module_paths: %d", _num_module_paths);
285 st->print_cr("- max_used_path_index: %d", _max_used_path_index);
286 st->print_cr("- verify_local: %d", _verify_local);
287 st->print_cr("- verify_remote: %d", _verify_remote);
288 st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes);
289 st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath);
290 st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
291 st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
292 st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
293 st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
294 st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_ptrmap_start_pos);
295 st->print_cr("- _rw_ptrmap_start_pos: " SIZE_FORMAT, _rw_ptrmap_start_pos);
296 st->print_cr("- _ro_ptrmap_start_pos: " SIZE_FORMAT, _ro_ptrmap_start_pos);
297 st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
298 st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
299 st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
300 }
301
302 void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
303 _type = non_existent_entry;
304 set_name(path, CHECK);
305 }
306
307 void SharedClassPathEntry::init(bool is_modules_image,
308 bool is_module_path,
309 ClassPathEntry* cpe, TRAPS) {
310 assert(CDSConfig::is_dumping_archive(), "sanity");
311 _timestamp = 0;
312 _filesize = 0;
313 _from_class_path_attr = false;
314
315 struct stat st;
316 if (os::stat(cpe->name(), &st) == 0) {
317 if ((st.st_mode & S_IFMT) == S_IFDIR) {
318 _type = dir_entry;
319 } else {
1334 if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) {
1335 log_info(cds)("_jvm_ident expected: %s", expected_ident);
1336 log_info(cds)(" actual: %s", actual_ident);
1337 log_warning(cds)("The shared archive file was created by a different"
1338 " version or build of HotSpot");
1339 return false;
1340 }
1341
1342 _file_offset = header()->header_size(); // accounts for the size of _base_archive_name
1343
1344 size_t len = os::lseek(fd, 0, SEEK_END);
1345
1346 for (int i = 0; i < MetaspaceShared::n_regions; i++) {
1347 FileMapRegion* r = region_at(i);
1348 if (r->file_offset() > len || len - r->file_offset() < r->used()) {
1349 log_warning(cds)("The shared archive file has been truncated.");
1350 return false;
1351 }
1352 }
1353
1354 return true;
1355 }
1356
1357 void FileMapInfo::seek_to_position(size_t pos) {
1358 if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) {
1359 log_error(cds)("Unable to seek to position " SIZE_FORMAT, pos);
1360 MetaspaceShared::unrecoverable_loading_error();
1361 }
1362 }
1363
1364 // Read the FileMapInfo information from the file.
1365 bool FileMapInfo::open_for_read() {
1366 if (_file_open) {
1367 return true;
1368 }
1369 log_info(cds)("trying to map %s", _full_path);
1370 int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
1371 if (fd < 0) {
1372 if (errno == ENOENT) {
1373 log_info(cds)("Specified shared archive not found (%s)", _full_path);
2442 // while AllowArchivingWithJavaAgent is set during the current run.
2443 if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) {
2444 log_warning(cds)("The setting of the AllowArchivingWithJavaAgent is different "
2445 "from the setting in the shared archive.");
2446 return false;
2447 }
2448
2449 if (_allow_archiving_with_java_agent) {
2450 log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used "
2451 "for testing purposes only and should not be used in a production environment");
2452 }
2453
2454 log_info(cds)("Archive was created with UseCompressedOops = %d, UseCompressedClassPointers = %d",
2455 compressed_oops(), compressed_class_pointers());
2456 if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) {
2457 log_info(cds)("Unable to use shared archive.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is "
2458 "different from runtime, CDS will be disabled.");
2459 return false;
2460 }
2461
2462 if (! _use_secondary_supers_table && UseSecondarySupersTable) {
2463 log_warning(cds)("The shared archive was created without UseSecondarySupersTable.");
2464 return false;
2465 }
2466
2467 if (!_use_optimized_module_handling) {
2468 CDSConfig::stop_using_optimized_module_handling();
2469 log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling");
2470 }
2471
2472 if (is_static() && !_has_full_module_graph) {
2473 // Only the static archive can contain the full module graph.
2474 CDSConfig::stop_using_full_module_graph("archive was created without full module graph");
2475 }
2476
2477 return true;
2478 }
2479
2480 bool FileMapInfo::validate_header() {
2481 if (!header()->validate()) {
|
64 #include "runtime/mutexLocker.hpp"
65 #include "runtime/os.hpp"
66 #include "runtime/vm_version.hpp"
67 #include "utilities/align.hpp"
68 #include "utilities/bitMap.inline.hpp"
69 #include "utilities/classpathStream.hpp"
70 #include "utilities/defaultStream.hpp"
71 #include "utilities/ostream.hpp"
72 #if INCLUDE_G1GC
73 #include "gc/g1/g1CollectedHeap.hpp"
74 #include "gc/g1/g1HeapRegion.hpp"
75 #endif
76
77 # include <sys/stat.h>
78 # include <errno.h>
79
80 #ifndef O_BINARY // if defined (Win32) use binary files.
81 #define O_BINARY 0 // otherwise do nothing.
82 #endif
83
84 inline void CDSMustMatchFlags::do_print(outputStream* st, bool v) {
85 st->print("%s", v ? "true" : "false");
86 }
87
88 inline void CDSMustMatchFlags::do_print(outputStream* st, intx v) {
89 st->print(INTX_FORMAT, v);
90 }
91
92 inline void CDSMustMatchFlags::do_print(outputStream* st, uintx v) {
93 st->print(UINTX_FORMAT, v);
94 }
95
96 inline void CDSMustMatchFlags::do_print(outputStream* st, double v) {
97 st->print("%f", v);
98 }
99
100 void CDSMustMatchFlags::init() {
101 assert(CDSConfig::is_dumping_archive(), "sanity");
102 _max_name_width = 0;
103
104 #define INIT_CDS_MUST_MATCH_FLAG(n) \
105 _v_##n = n; \
106 _max_name_width = MAX2(_max_name_width,strlen(#n));
107 CDS_MUST_MATCH_FLAGS_DO(INIT_CDS_MUST_MATCH_FLAG);
108 #undef INIT_CDS_MUST_MATCH_FLAG
109 }
110
111 bool CDSMustMatchFlags::runtime_check() const {
112 #define CHECK_CDS_MUST_MATCH_FLAG(n) \
113 if (_v_##n != n) { \
114 ResourceMark rm; \
115 stringStream ss; \
116 ss.print("VM option %s is different between dumptime (", #n); \
117 do_print(&ss, _v_ ## n); \
118 ss.print(") and runtime ("); \
119 do_print(&ss, n); \
120 ss.print(")"); \
121 log_info(cds)("%s", ss.as_string()); \
122 return false; \
123 }
124 CDS_MUST_MATCH_FLAGS_DO(CHECK_CDS_MUST_MATCH_FLAG);
125 #undef CHECK_CDS_MUST_MATCH_FLAG
126
127 return true;
128 }
129
130 void CDSMustMatchFlags::print_info() const {
131 LogTarget(Info, cds) lt;
132 if (lt.is_enabled()) {
133 LogStream ls(lt);
134 ls.print_cr("Recorded VM flags during dumptime:");
135 print(&ls);
136 }
137 }
138
139 void CDSMustMatchFlags::print(outputStream* st) const {
140 #define PRINT_CDS_MUST_MATCH_FLAG(n) \
141 st->print("- %-s ", #n); \
142 st->sp(int(_max_name_width - strlen(#n))); \
143 do_print(st, _v_##n); \
144 st->cr();
145 CDS_MUST_MATCH_FLAGS_DO(PRINT_CDS_MUST_MATCH_FLAG);
146 #undef PRINT_CDS_MUST_MATCH_FLAG
147 }
148
149 // Fill in the fileMapInfo structure with data about this VM instance.
150
151 // This method copies the vm version info into header_version. If the version is too
152 // long then a truncated version, which has a hash code appended to it, is copied.
153 //
154 // Using a template enables this method to verify that header_version is an array of
155 // length JVM_IDENT_MAX. This ensures that the code that writes to the CDS file and
156 // the code that reads the CDS file will both use the same size buffer. Hence, will
157 // use identical truncation. This is necessary for matching of truncated versions.
158 template <int N> static void get_header_version(char (&header_version) [N]) {
159 assert(N == JVM_IDENT_MAX, "Bad header_version size");
160
161 const char *vm_version = VM_Version::internal_vm_info_string();
162 const int version_len = (int)strlen(vm_version);
163
164 memset(header_version, 0, JVM_IDENT_MAX);
165
166 if (version_len < (JVM_IDENT_MAX-1)) {
167 strcpy(header_version, vm_version);
168
263 set_version(CURRENT_CDS_ARCHIVE_VERSION);
264
265 if (!info->is_static() && base_archive_name_size != 0) {
266 // copy base archive name
267 copy_base_archive_name(CDSConfig::static_archive_path());
268 }
269 _core_region_alignment = core_region_alignment;
270 _obj_alignment = ObjectAlignmentInBytes;
271 _compact_strings = CompactStrings;
272 if (CDSConfig::is_dumping_heap()) {
273 _narrow_oop_mode = CompressedOops::mode();
274 _narrow_oop_base = CompressedOops::base();
275 _narrow_oop_shift = CompressedOops::shift();
276 }
277 _compressed_oops = UseCompressedOops;
278 _compressed_class_ptrs = UseCompressedClassPointers;
279 _use_secondary_supers_table = UseSecondarySupersTable;
280 _max_heap_size = MaxHeapSize;
281 _use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
282 _has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
283 _has_valhalla_patched_classes = CDSConfig::is_valhalla_preview();
284 // The following fields are for sanity checks for whether this archive
285 // will function correctly with this JVM and the bootclasspath it's
286 // invoked with.
287
288 // JVM version string ... changes on each build.
289 get_header_version(_jvm_ident);
290
291 _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
292 _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
293 _max_used_path_index = ClassLoaderExt::max_used_path_index();
294 _num_module_paths = ClassLoader::num_module_path_entries();
295
296 _verify_local = BytecodeVerificationLocal;
297 _verify_remote = BytecodeVerificationRemote;
298 _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
299 _has_non_jar_in_classpath = ClassLoaderExt::has_non_jar_in_classpath();
300 _requested_base_address = (char*)SharedBaseAddress;
301 _mapped_base_address = (char*)SharedBaseAddress;
302 _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
303 _must_match.init();
304
305 if (!CDSConfig::is_dumping_dynamic_archive()) {
306 set_shared_path_table(info->_shared_path_table);
307 }
308 }
309
310 void FileMapHeader::copy_base_archive_name(const char* archive) {
311 assert(base_archive_name_size() != 0, "_base_archive_name_size not set");
312 assert(base_archive_name_offset() != 0, "_base_archive_name_offset not set");
313 assert(header_size() > sizeof(*this), "_base_archive_name_size not included in header size?");
314 memcpy((char*)this + base_archive_name_offset(), archive, base_archive_name_size());
315 }
316
317 void FileMapHeader::print(outputStream* st) {
318 ResourceMark rm;
319
320 st->print_cr("- magic: 0x%08x", magic());
321 st->print_cr("- crc: 0x%08x", crc());
322 st->print_cr("- version: 0x%x", version());
323 st->print_cr("- header_size: " UINT32_FORMAT, header_size());
346 st->print_cr("- jvm_ident: %s", _jvm_ident);
347 st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_X, _shared_path_table_offset);
348 st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index);
349 st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index);
350 st->print_cr("- num_module_paths: %d", _num_module_paths);
351 st->print_cr("- max_used_path_index: %d", _max_used_path_index);
352 st->print_cr("- verify_local: %d", _verify_local);
353 st->print_cr("- verify_remote: %d", _verify_remote);
354 st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes);
355 st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath);
356 st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
357 st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
358 st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
359 st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
360 st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_ptrmap_start_pos);
361 st->print_cr("- _rw_ptrmap_start_pos: " SIZE_FORMAT, _rw_ptrmap_start_pos);
362 st->print_cr("- _ro_ptrmap_start_pos: " SIZE_FORMAT, _ro_ptrmap_start_pos);
363 st->print_cr("- allow_archiving_with_java_agent:%d", _allow_archiving_with_java_agent);
364 st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
365 st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
366 st->print_cr("- has_valhalla_patched_classes %d", _has_valhalla_patched_classes);
367 _must_match.print(st);
368 }
369
370 void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
371 _type = non_existent_entry;
372 set_name(path, CHECK);
373 }
374
375 void SharedClassPathEntry::init(bool is_modules_image,
376 bool is_module_path,
377 ClassPathEntry* cpe, TRAPS) {
378 assert(CDSConfig::is_dumping_archive(), "sanity");
379 _timestamp = 0;
380 _filesize = 0;
381 _from_class_path_attr = false;
382
383 struct stat st;
384 if (os::stat(cpe->name(), &st) == 0) {
385 if ((st.st_mode & S_IFMT) == S_IFDIR) {
386 _type = dir_entry;
387 } else {
1402 if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) {
1403 log_info(cds)("_jvm_ident expected: %s", expected_ident);
1404 log_info(cds)(" actual: %s", actual_ident);
1405 log_warning(cds)("The shared archive file was created by a different"
1406 " version or build of HotSpot");
1407 return false;
1408 }
1409
1410 _file_offset = header()->header_size(); // accounts for the size of _base_archive_name
1411
1412 size_t len = os::lseek(fd, 0, SEEK_END);
1413
1414 for (int i = 0; i < MetaspaceShared::n_regions; i++) {
1415 FileMapRegion* r = region_at(i);
1416 if (r->file_offset() > len || len - r->file_offset() < r->used()) {
1417 log_warning(cds)("The shared archive file has been truncated.");
1418 return false;
1419 }
1420 }
1421
1422 if (!header()->check_must_match_flags()) {
1423 return false;
1424 }
1425
1426 return true;
1427 }
1428
1429 void FileMapInfo::seek_to_position(size_t pos) {
1430 if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) {
1431 log_error(cds)("Unable to seek to position " SIZE_FORMAT, pos);
1432 MetaspaceShared::unrecoverable_loading_error();
1433 }
1434 }
1435
1436 // Read the FileMapInfo information from the file.
1437 bool FileMapInfo::open_for_read() {
1438 if (_file_open) {
1439 return true;
1440 }
1441 log_info(cds)("trying to map %s", _full_path);
1442 int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
1443 if (fd < 0) {
1444 if (errno == ENOENT) {
1445 log_info(cds)("Specified shared archive not found (%s)", _full_path);
2514 // while AllowArchivingWithJavaAgent is set during the current run.
2515 if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) {
2516 log_warning(cds)("The setting of the AllowArchivingWithJavaAgent is different "
2517 "from the setting in the shared archive.");
2518 return false;
2519 }
2520
2521 if (_allow_archiving_with_java_agent) {
2522 log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used "
2523 "for testing purposes only and should not be used in a production environment");
2524 }
2525
2526 log_info(cds)("Archive was created with UseCompressedOops = %d, UseCompressedClassPointers = %d",
2527 compressed_oops(), compressed_class_pointers());
2528 if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) {
2529 log_info(cds)("Unable to use shared archive.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is "
2530 "different from runtime, CDS will be disabled.");
2531 return false;
2532 }
2533
2534 if (is_static()) {
2535 const char* err = nullptr;
2536 if (CDSConfig::is_valhalla_preview()) {
2537 if (!_has_valhalla_patched_classes) {
2538 err = "not created";
2539 }
2540 } else {
2541 if (_has_valhalla_patched_classes) {
2542 err = "created";
2543 }
2544 }
2545 if (err != nullptr) {
2546 log_warning(cds)("This archive was %s with --enable-preview -XX:+EnableValhalla. It is "
2547 "incompatible with the current JVM setting", err);
2548 return false;
2549 }
2550 }
2551
2552 if (! _use_secondary_supers_table && UseSecondarySupersTable) {
2553 log_warning(cds)("The shared archive was created without UseSecondarySupersTable.");
2554 return false;
2555 }
2556
2557 if (!_use_optimized_module_handling) {
2558 CDSConfig::stop_using_optimized_module_handling();
2559 log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling");
2560 }
2561
2562 if (is_static() && !_has_full_module_graph) {
2563 // Only the static archive can contain the full module graph.
2564 CDSConfig::stop_using_full_module_graph("archive was created without full module graph");
2565 }
2566
2567 return true;
2568 }
2569
2570 bool FileMapInfo::validate_header() {
2571 if (!header()->validate()) {
|