1818//
1919// memcpy(owned_table, line_number_table, bytes);
2020//
21- // (flightRecorder.cpp now guards this copy with SafeAccess::isReadableRange()
22- // -- see below -- so the line numbers of the unguarded version are no longer
23- // present in the file; this file's tests reproduce that removed pattern.)
21+ // (flightRecorder.cpp now guards this copy with SafeAccess::safeCopy() -- see
22+ // below -- so the line numbers of the unguarded version are no longer present
23+ // in the file; this file's tests reproduce that removed pattern. An earlier
24+ // version of the fix used a separate SafeAccess::isReadableRange() probe
25+ // followed by a plain memcpy(), but that still left a check-then-use race:
26+ // nothing stops the probed memory from becoming invalid in the gap between
27+ // the probe and the copy. safeCopy() closes that gap by fault-protecting
28+ // each read as it happens instead of trusting a point-in-time check.)
2429//
2530// Unlike the class_name/method_name/method_sig strings returned by the
2631// preceding JVMTI calls (which ARE probed with SafeAccess::isReadableRange
@@ -152,10 +157,10 @@ TEST(LineNumberTableCopyRawTest, UnguardedCopyCrashesWhenSourceUnmapped) {
152157 " " );
153158}
154159
155- // Documents the fix: guarding the same copy with
156- // SafeAccess::isReadableRange() (the same primitive already used to probe
157- // class_name/method_name/method_sig in fillJavaMethodInfo) turns the crash
158- // into a clean, detectable failure with no memory touched past the guard .
160+ // Documents the fix: copying via SafeAccess::safeCopy() (which fault-protects
161+ // each read as it happens, rather than a point-in-time isReadableRange()
162+ // probe followed by a separate, unprotected memcpy()) turns the crash into a
163+ // clean, detectable failure with no memory touched past the fault .
159164TEST_F (LineNumberTableCopyTest, GuardedCopySkipsSafelyWhenSourceUnmapped) {
160165 long page_size = sysconf (_SC_PAGESIZE);
161166 void *page = mmap (NULL , page_size, PROT_READ | PROT_WRITE ,
@@ -169,14 +174,14 @@ TEST_F(LineNumberTableCopyTest, GuardedCopySkipsSafelyWhenSourceUnmapped) {
169174 ASSERT_EQ (0 , munmap (page, page_size));
170175
171176 size_t bytes = (size_t )line_number_table_size * sizeof (jvmtiLineNumberEntry);
172- void *owned_table = nullptr ;
173- if (SafeAccess::isReadableRange (line_number_table, bytes)) {
174- owned_table = malloc (bytes);
175- memcpy (owned_table, line_number_table, bytes);
177+ void *owned_table = malloc (bytes);
178+ ASSERT_NE (owned_table, nullptr );
179+ if (!SafeAccess::safeCopy (owned_table, line_number_table, bytes)) {
180+ free (owned_table);
181+ owned_table = nullptr ;
176182 }
177183
178184 EXPECT_EQ (nullptr , owned_table);
179- free (owned_table);
180185}
181186
182187// Sanity check: the guard must not reject a genuinely valid table, or every
@@ -188,10 +193,11 @@ TEST_F(LineNumberTableCopyTest, GuardedCopyStillWorksForValidSource) {
188193 makeFakeLineNumberTable (stack_table, line_number_table_size);
189194
190195 size_t bytes = (size_t )line_number_table_size * sizeof (jvmtiLineNumberEntry);
191- void *owned_table = nullptr ;
192- if (SafeAccess::isReadableRange (line_number_table, bytes)) {
193- owned_table = malloc (bytes);
194- memcpy (owned_table, line_number_table, bytes);
196+ void *owned_table = malloc (bytes);
197+ ASSERT_NE (owned_table, nullptr );
198+ if (!SafeAccess::safeCopy (owned_table, line_number_table, bytes)) {
199+ free (owned_table);
200+ owned_table = nullptr ;
195201 }
196202
197203 ASSERT_NE (nullptr , owned_table);
0 commit comments