Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-Version: 5.1.0.qualifier
Bundle-Version: 5.2.0.qualifier
Bundle-Localization: plugin
Bundle-SymbolicName: org.eclipse.tracecompass.ctf.core;singleton:=true
Bundle-ActivationPolicy: lazy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;

/**
* A CTF blob class definition.
* A CTF blob class declaration.
*
* The definition of a blob data type that can be used to define sequence of
* The declaration of a blob data type that can be used to define sequence of
* zero or more contiguous bytes with an associated IANA media type
*
* @author Sehr Moosabhoy
Expand Down Expand Up @@ -85,7 +85,8 @@ public long getAlignment() {

@Override
public int getMaximumSize() {
return fLength * 8; // This will allow the blob to be read properly and not break alignment in ctf.
return fLength * 8; // This will allow the blob to be read properly and
// not break alignment in ctf.
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ public byte[] getBytes() {
return fArray;
}

/**
* @return
* @since 5.2
*/
public String getType() {
return fType;
}

@Override
public @NonNull BlobDeclaration getDeclaration() {
return (BlobDeclaration) super.getDeclaration();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**********************************************************************
* Copyright (c) 2026 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.ctf.core.event.types;

import java.nio.ByteOrder;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;

/**
* A CTF declaration of a boolean field
*
* It declares a certain amount of bits as a boolean value.
*
* @since 5.2
* @author Arnaud Fiorini
*/
public class BooleanDeclaration extends Declaration {

private int fLength;
private long fAlignment;
private ByteOrder fByteOrder;

/**
* @param length
* the size of the boolean field
* @param byteOrder
* the order in which the bytes should be read
* @param alignment
* alignment of the first bit of field relative to the beginning
* of the packet
*/
public BooleanDeclaration(int length, ByteOrder byteOrder, long alignment) {
fLength = length;
fByteOrder = byteOrder;
fAlignment = alignment;
}

@Override
public @NonNull Definition createDefinition(IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull BitBuffer input) throws CTFException {
ByteOrder byteOrder = input.getByteOrder();
input.setByteOrder(fByteOrder);
boolean value = read(input);
input.setByteOrder(byteOrder);
return new BooleanDefinition(this, definitionScope, fieldName, value);
Comment thread
arfio marked this conversation as resolved.
}

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;
}
}
Comment on lines +58 to +63
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.

return false;
}

@Override
public long getAlignment() {
return fAlignment;
}

@Override
public int getMaximumSize() {
return fLength;
}

@Override
public boolean isBinaryEquivalent(IDeclaration other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (getClass() != other.getClass()) {
return false;
}
return fLength == other.getMaximumSize();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**********************************************************************
* Copyright (c) 2026 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.ctf.core.event.types;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;

/**
* A CTF2 boolean definition.
*
* The definition of a boolean field class in ctf2
*
* @author Arnaud Fiorini
* @since 5.2
*/
public class BooleanDefinition extends SimpleDatatypeDefinition {

private final boolean fValue;

/**
* Constructor
*
* @param declaration
* the parent declaration
* @param definitionScope
* the parent scope
* @param fieldName
* the field name
* @param value
* the field value
*/
public BooleanDefinition(@NonNull IDeclaration declaration, IDefinitionScope definitionScope, @NonNull String fieldName, boolean value) {
super(declaration, definitionScope, fieldName);
fValue = value;
}

/**
* @return boolean value of the field
*/
public boolean getValue() {
return fValue;
}

@Override
public BooleanDeclaration getDeclaration() {
return (BooleanDeclaration) super.getDeclaration();
}

@Override
public String toString() {
return String.valueOf(fValue);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**********************************************************************
* Copyright (c) 2026 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.ctf.core.event.types;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;

/**
* A CTF blob class declaration.
*
* The declaration of a blob data type that can be used to define sequence of
* zero or more contiguous bytes with an associated IANA media type
*
* @since 5.2
* @author Arnaud Fiorini
*/
public class DynamicBlobDeclaration extends Declaration {

private String fLengthName;
private String fMediaType;

/**
* Constructor
*
* @param lengthName
* the length field location
* @param mediaType
* the IANA media type
*/
public DynamicBlobDeclaration(@Nullable String lengthName, String mediaType) {
fLengthName = lengthName;
fMediaType = mediaType;
Comment on lines +41 to +43
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.

}

@Override
public @NonNull Definition createDefinition(IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull BitBuffer input) throws CTFException {
IDefinition lenDef = null;

if (definitionScope != null) {
lenDef = definitionScope.lookupDefinition(fLengthName);
}

if (lenDef == null) {
throw new CTFException("Dynamic blob length field not found"); //$NON-NLS-1$
}

if (!(lenDef instanceof IntegerDefinition)) {
throw new CTFException("Dynamic blob length field not integer"); //$NON-NLS-1$
}

IntegerDefinition lengthDefinition = (IntegerDefinition) lenDef;

if (lengthDefinition.getDeclaration().isSigned()) {
throw new CTFException("Dynamic blob length must not be signed"); //$NON-NLS-1$
}

long length = lengthDefinition.getValue();
if ((length > Integer.MAX_VALUE) || (!input.canRead((int) length))) {
throw new CTFException("Blob is too large " + length); //$NON-NLS-1$
}

byte[] array = new byte[(int) length];
if (input.getByteBuffer().remaining() < length) {
throw new CTFException("There is not enough data provided. Length asked: " + length + " Remaining buffer size: " + input.getByteBuffer().remaining()); //$NON-NLS-1$ //$NON-NLS-2$
}

/* Offset the buffer position wrt the current alignment */
alignRead(input);
input.get(array);

return new DynamicBlobDefinition(this, definitionScope, fieldName, array, fMediaType);
}

@Override
public int getMaximumSize() {
return Integer.MAX_VALUE;
}

/**
* From the documentation:
* https://diamon.org/ctf/files/CTF2-SPECRC-7.0rA.html#align-dec
*
* Alignment of a blob will always be 8 bits
*/
@Override
public long getAlignment() {
return 8;
}

@Override
public String toString() {
/* Only used for debugging */
return "[declaration] dynamicblob[length-field-location=" + fLengthName + ", media-type=" + fMediaType + ']'; //$NON-NLS-1$ //$NON-NLS-2$
}

@Override
public boolean isBinaryEquivalent(IDeclaration other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (getClass() != other.getClass()) {
return false;
}
DynamicBlobDeclaration otherBlob = (DynamicBlobDeclaration) other;
if (!fMediaType.equals(otherBlob.fMediaType)) {
return false;
}
return (fLengthName.equals(otherBlob.fLengthName));
}
}
Loading
Loading