Skip to content

ctf: Add new field classes to complete ctf2 parsing#400

Open
arfio wants to merge 1 commit into
eclipse-tracecompass:masterfrom
arfio:ctf2-fixes
Open

ctf: Add new field classes to complete ctf2 parsing#400
arfio wants to merge 1 commit into
eclipse-tracecompass:masterfrom
arfio:ctf2-fixes

Conversation

@arfio
Copy link
Copy Markdown
Contributor

@arfio arfio commented May 22, 2026

What it does

  • Add the support for the following ctf2 field classes: Fixed-length boolean field class and Dynamic-length BLOB field class
  • Fixes part of CTF2 Field classes missing #376

How to test

Follow-ups

  • Support for fixed-length-bit-map, fixed-length-bit-array, optional

Review checklist

  • As an author, I have thoroughly tested my changes and carefully followed the instructions in this template

Summary by CodeRabbit

  • New Features
    • Added support for boolean CTF field types with configurable alignment and byte order
    • Added support for dynamic-length blob (binary data) field types with media-type information
    • Enhanced blob field representation and display capabilities

Review Change Stack

Signed-off-by: Arnaud Fiorini <fiorini.arnaud@gmail.com>
@arfio arfio requested a review from MatthewKhouzam May 22, 2026 13:54
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

This PR adds boolean and dynamic blob field types to the CTF core event system, including declaration/definition pairs, TSDL metadata parsing, type alias integration, and event field rendering. The bundle version is bumped to 5.2.0.

Changes

CTF Type System Expansion: Boolean and Dynamic Blob Support

Layer / File(s) Summary
Metadata Constants and Version
ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF, src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
Bundle version updated to 5.2.0.qualifier. New JSON metadata constants introduced for FIXED_LENGTH_BOOLEAN, FIXED_LENGTH_BIT_ARRAY, FIXED_LENGTH_BIT_MAP, DYNAMIC_LENGTH_BLOB, and OPTIONAL field types.
Boolean Field Type Declaration and Definition
src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java, BooleanDeclaration.java, BooleanDefinition.java, src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/bool/BooleanDeclarationParser.java
BooleanDeclaration implements bitstream parsing with configurable length, byte order, and alignment; BooleanDefinition holds immutable boolean values. BooleanDeclarationParser validates TSDL metadata and constructs boolean declarations. Javadoc in BlobDeclaration clarified to use "declaration" terminology.
Dynamic Blob Field Type Declaration and Definition
src/org/eclipse/tracecompass/ctf/core/event/types/BlobDefinition.java, DynamicBlobDeclaration.java, DynamicBlobDefinition.java, src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/DynamicBlobDeclarationParser.java, BlobDeclarationParser.java
DynamicBlobDeclaration resolves variable-length blobs by reading from referenced integer fields and extracts bytes into DynamicBlobDefinition. DynamicBlobDeclarationParser parses TSDL metadata including length-field-location and media-type. BlobDefinition gains getType() accessor. BlobDeclarationParser corrected to use constant for media-type key check.
Type Alias Parser Integration
src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
Parser now imports BooleanDeclarationParser and recognizes FIXED_LENGTH_BOOLEAN and DYNAMIC_LENGTH_BLOB field types in the type-alias switch, routing them to corresponding parsers. Placeholder branches added for future bit array and bit map support.
Event Field Rendering Integration
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
CtfTmfEventField.parseField() recognizes BlobDefinition and DynamicBlobDefinition instances and creates CTFHexBlobField for rendering. New CTFHexBlobField class encodes blob bytes in Base64 and includes media type in string representation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • bhufmann
  • PatrickTasse

Poem

🐰 In the CTF's shifting streams, new types take their stand,
Booleans flip like springtime snow, blobs dance through the land,
With metadata parsers guiding paths and Base64 dreams,
The tracecompass now captures truth in dynamic, glowing beams!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding new field classes to complete CTF2 parsing, which is the core objective reflected throughout the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)

583-599: ⚡ Quick win

Cache formatted blob output to avoid repeated Base64 work.

getFormattedValue() re-encodes bytes on every call; with dynamic blobs this can become expensive in repeated rendering paths. Cache the formatted string once (same pattern already used by other field classes here).

♻️ Proposed refactor
 final class CTFHexBlobField extends CtfTmfEventField {
 
-    private String fBlobType;
+    private final String fBlobType;
+    private `@Nullable` String fFormattedValue;
@@
     `@Override`
-    public String getFormattedValue() {
-        String encoded = Base64.getEncoder().encodeToString(getValue());
-        return "[" + fBlobType + "]<" + encoded + '>'; //$NON-NLS-1$ //$NON-NLS-2$
+    public synchronized String getFormattedValue() {
+        if (fFormattedValue == null) {
+            String encoded = Base64.getEncoder().encodeToString(getValue());
+            fFormattedValue = "[" + fBlobType + "]<" + encoded + '>'; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        return fFormattedValue;
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java`
around lines 583 - 599, getFormattedValue() currently Base64-encodes getValue()
on every call; add a lazily-initialized cached String field (e.g.,
fFormattedValue) on CTFHexBlobField and compute the "[" + fBlobType + "]<" +
Base64.getEncoder().encodeToString(getValue()) + '>' only once in
getFormattedValue(), store it in the cache and return the cached value on
subsequent calls; follow the same lazy-cache pattern and naming conventions used
by other field classes, and make the cache safe for concurrent reads (e.g., a
volatile field or simple double-check idiom) so repeated rendering avoids
repeated Base64 work.
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDefinition.java (1)

58-60: ⚡ Quick win

Return a defensive copy from getBytes().

getBytes() currently exposes internal mutable state. Any caller can mutate fArray and alter this definition instance unexpectedly.

Proposed fix
     `@Override`
     public byte[] getBytes() {
-        return fArray;
+        return fArray.clone();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDefinition.java`
around lines 58 - 60, DynamicBlobDefinition.getBytes exposes the internal
mutable byte[] fArray; change getBytes() to return a defensive copy (e.g., clone
or Arrays.copyOf) of fArray instead of the array reference, and handle the null
case consistently (return null or an empty array as appropriate) so callers
cannot mutate the internal state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BooleanDeclaration.java`:
- Around line 50-55: In createDefinition, ensure the original ByteOrder
(variable byteOrder) is always restored on the BitBuffer even if read(input)
throws: wrap the call to read(input) (and any code that depends on the temporary
fByteOrder) in a try/finally and call input.setByteOrder(byteOrder) in the
finally block so the buffer state is restored before returning or propagating
the exception; reference createDefinition, read(Input)/read(input), fByteOrder,
input.setByteOrder(...), and BooleanDefinition to locate the change.
- Around line 58-63: The BooleanDeclaration.read method incorrectly increments
the chunk index by 1 bit; change the loop to advance by 64-bit chunks and
compute the remaining bits per iteration. Specifically, in read(BitBuffer input)
update the for-loop to iterate with "for (int i = 0; i < fLength; i += 64)" and
use "int remaining = fLength - i" then call input.get(Math.min(64, remaining),
false) so BitBuffer.get is always passed a valid chunk length and the reader
advances by full 64-bit chunks.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDeclaration.java`:
- Around line 41-43: The constructor DynamicBlobDeclaration currently accepts a
nullable lengthName and stores it in fLengthName, but later code (including
other occurrences around the constructor and at the usages noted) dereferences
or compares fLengthName directly; modify all comparisons and dereferences of
fLengthName (including in methods referenced near lines 51-52 and 122-123) to
handle null safely by using null-safe checks (e.g., check fLengthName != null
before calling equals/compare, or use Objects.equals(fLengthName, other) /
Objects.equals(other, fLengthName)) and avoid direct method calls on fLengthName
when it may be null, ensuring the constructor and any equality/lookup logic
account for a null lengthName value.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/DynamicBlobDeclarationParser.java`:
- Around line 72-79: The code currently dereferences
lengthFieldLocation/length-field-location.path without validation in
DynamicBlobDeclarationParser, which can cause runtime exceptions; update the
parsing logic to first confirm lengthFieldLocation.isJsonObject() and that the
object has JsonMetadataStrings.PATH, then ensure the path element is either a
non-empty JsonArray whose last element is a JsonPrimitive string or a
JsonPrimitive string; if any check fails (missing path, path not
object/array/string, empty array, or non-string last element) throw a
ParseException with a clear message; replace direct calls to
getAsJsonObject/getAsJsonArray/getAsString for
lengthFieldLocation/pathElement/lengthName with guarded checks that produce
deterministic ParseException errors.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java`:
- Around line 196-201: The switch branches for
JsonMetadataStrings.FIXED_LENGTH_BIT_ARRAY and
JsonMetadataStrings.FIXED_LENGTH_BIT_MAP in TypeAliasParser currently break
without assigning targetDeclaration, which later causes a null registration;
change these branches to throw a ParseException (with a clear message mentioning
the unsupported field class) instead of breaking so parsing fails fast. Locate
the switch handling field class in TypeAliasParser (the cases for
FIXED_LENGTH_BIT_ARRAY and FIXED_LENGTH_BIT_MAP) and replace the break logic
with code that raises a ParseException referencing the offending field class and
the alias name being processed, ensuring the method never reaches the later
register-type-alias path with a null targetDeclaration.

---

Nitpick comments:
In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDefinition.java`:
- Around line 58-60: DynamicBlobDefinition.getBytes exposes the internal mutable
byte[] fArray; change getBytes() to return a defensive copy (e.g., clone or
Arrays.copyOf) of fArray instead of the array reference, and handle the null
case consistently (return null or an empty array as appropriate) so callers
cannot mutate the internal state.

In
`@ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java`:
- Around line 583-599: getFormattedValue() currently Base64-encodes getValue()
on every call; add a lazily-initialized cached String field (e.g.,
fFormattedValue) on CTFHexBlobField and compute the "[" + fBlobType + "]<" +
Base64.getEncoder().encodeToString(getValue()) + '>' only once in
getFormattedValue(), store it in the cache and return the cached value on
subsequent calls; follow the same lazy-cache pattern and naming conventions used
by other field classes, and make the cache safe for concurrent reads (e.g., a
volatile field or simple double-check idiom) so repeated rendering avoids
repeated Base64 work.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26a2a8a9-0946-48b0-805a-b76f0a0e7a86

📥 Commits

Reviewing files that changed from the base of the PR and between 3c40d1c and 4773240.

📒 Files selected for processing (13)
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BooleanDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BooleanDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/BlobDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/DynamicBlobDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/bool/BooleanDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java

Comment on lines +58 to +63
private boolean read(BitBuffer input) throws CTFException {
for (int i = 0; i < fLength; i++) {
if (input.get(Math.min(64, fLength - i * 64), false) != 0) {
return true;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix chunk iteration in boolean bit reader.

The loop advances by 1 bit-index but subtracts i * 64, so after the first iteration it can request invalid lengths and misread input for booleans wider than 1 bit.

Proposed fix
     private boolean read(BitBuffer input) throws CTFException {
-        for (int i = 0; i < fLength; i++) {
-            if (input.get(Math.min(64, fLength - i * 64), false) != 0) {
+        int remaining = fLength;
+        while (remaining > 0) {
+            int chunkSize = Math.min(64, remaining);
+            if (input.get(chunkSize, false) != 0) {
                 return true;
             }
+            remaining -= chunkSize;
         }
         return false;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BooleanDeclaration.java`
around lines 58 - 63, The BooleanDeclaration.read method incorrectly increments
the chunk index by 1 bit; change the loop to advance by 64-bit chunks and
compute the remaining bits per iteration. Specifically, in read(BitBuffer input)
update the for-loop to iterate with "for (int i = 0; i < fLength; i += 64)" and
use "int remaining = fLength - i" then call input.get(Math.min(64, remaining),
false) so BitBuffer.get is always passed a valid chunk length and the reader
advances by full 64-bit chunks.

Comment on lines +41 to +43
public DynamicBlobDeclaration(@Nullable String lengthName, String mediaType) {
fLengthName = lengthName;
fMediaType = mediaType;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Guard nullable lengthName and compare safely.

fLengthName is nullable at construction but later dereferenced directly, which can cause runtime failures.

Proposed fix
+import java.util.Objects;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
@@
-    private String fLengthName;
-    private String fMediaType;
+    private final `@Nullable` String fLengthName;
+    private final String fMediaType;
@@
     public `@NonNull` Definition createDefinition(IDefinitionScope definitionScope, `@NonNull` String fieldName, `@NonNull` BitBuffer input) throws CTFException {
+        if (fLengthName == null || fLengthName.isBlank()) {
+            throw new CTFException("Dynamic blob length field location is missing"); //$NON-NLS-1$
+        }
         IDefinition lenDef = null;
@@
-        return (fLengthName.equals(otherBlob.fLengthName));
+        return Objects.equals(fLengthName, otherBlob.fLengthName);
     }

Also applies to: 51-52, 122-123

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/DynamicBlobDeclaration.java`
around lines 41 - 43, The constructor DynamicBlobDeclaration currently accepts a
nullable lengthName and stores it in fLengthName, but later code (including
other occurrences around the constructor and at the usages noted) dereferences
or compares fLengthName directly; modify all comparisons and dereferences of
fLengthName (including in methods referenced near lines 51-52 and 122-123) to
handle null safely by using null-safe checks (e.g., check fLengthName != null
before calling equals/compare, or use Objects.equals(fLengthName, other) /
Objects.equals(other, fLengthName)) and avoid direct method calls on fLengthName
when it may be null, ensuring the constructor and any equality/lookup logic
account for a null lengthName value.

Copy link
Copy Markdown
Contributor

@MatthewKhouzam MatthewKhouzam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. add unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants