RFR: 8289688: jfr command hangs when it processes invalid file [v2]

Yasumasa Suenaga ysuenaga at openjdk.org
Mon Jul 25 15:42:06 UTC 2022


On Mon, 25 Jul 2022 13:30:03 GMT, Erik Gahlin <egahlin at openjdk.org> wrote:

>> `ChunkHeader::refresh` need to satisfy to exit loop following conditions:
>> 
>> * File state is "stable" (get same state twice (L123 and L131))
>> * `metadataPosition` is not (greater than) 0
>> 
>> `fileState1` comes from `readFileState()` which uses `pollWait()` as you mentioned, so we can deem the recording data is "stable" if L134 is true.
>> 
>> 
>> 123             byte fileState1 = readFileState();
>>  :
>> 131             byte fileState2 =  input.readPhysicalByte();
>> 132             input.positionPhysical(absoluteChunkStart + FLAG_BYTE_POSITION);
>> 133             int flagByte = input.readPhysicalByte();
>> 134             if (fileState1 == fileState2) { // valid header
>> 135                 finished = fileState1 == 0;
>> 136                 if (metadataPosition != 0) {
>>  :
>> 164                     return;
>> 165                 }
>> 
>> 
>> In addition, we can deem that recording data would not be updated if `finished` is set to `true` in L135. Thus I think we can fix this problem with following patch. How about this?
>> 
>> 
>> diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> index 8c8ec55f0da..8648c030f06 100644
>> --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> @@ -162,6 +162,8 @@ public final class ChunkHeader {
>>                      Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: finalChunk=" + finalChunk);
>>                      absoluteChunkEnd = absoluteChunkStart + chunkSize;
>>                      return;
>> +                } else if (finished) {
>> +                    throw new IOException("metadataPosition is 0 but chunk header is valid.");
>>                  }
>>              }
>>          }
>> 
>> 
>> I understand that producer (Native Image in this case) should be fixed not to out invalid recording file. However we need to notify errors when the user passes invalid file to jfr command. So I've proposed this to jdk project.
>
>> diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> index 8c8ec55f0da..8648c030f06 100644
>> --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
>> @@ -162,6 +162,8 @@ public final class ChunkHeader {
>>                      Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: finalChunk=" + finalChunk);
>>                      absoluteChunkEnd = absoluteChunkStart + chunkSize;
>>                      return;
>> +                } else if (finished) {
>> +                    throw new IOException("metadataPosition is 0 but chunk header is valid.");
>>                  }
>>              }
>>          }
>> ```
>> 
> 
> This may work, values are read reliably and when a chunk is finished, it should always have metadata section, or something is wrong with the file. 
> 
> That said, when the file format was designed the metadata pointer in the header was meant as a hint (not a mandatory thing) to prevent a parser for reading the file twice. Neither JMC or JDK parser supports reading recordings without the metadata pointer hint AFAIK, so that ship may have sailed. If the use case should arrive, the ChunkHeader class must be modified anyway (and the above check replaced with an iteration over all the events to find the offset). 
> 
> Have you looked at the HotSpot implementation to make sure fileState is never 0, unless the metadata pointer hint has been written? If I remember correctly, the initial value is 1, but I haven't checked. I looked at the RemoteRecordingStream class and it looks like it can't happen there, if the output from the JVM is OK.
> 
> I think the message could be "No metadata event found in finished chunk".

Thanks @egahlin for your comment! I updated this PR with your suggestion.

> Have you looked at the HotSpot implementation to make sure fileState is never 0, unless the metadata pointer hint has been written?

In JfrChunkWriter.cpp, the file state is always set to `0` when a chunk is finalized.

```c++
101   void write_generation(bool finalize) {
102     _writer->be_write(finalize ? COMPLETE : _chunk->generation());
103     _writer->be_write(PAD);
104   }
105
106   void write_next_generation(bool finalize) {
107     _writer->be_write(finalize ? COMPLETE : _chunk->next_generation());
108     _writer->be_write(PAD);
109   }

-------------

PR: https://git.openjdk.org/jdk/pull/9363


More information about the hotspot-jfr-dev mailing list