Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8261578: jextract crashes with Crossing storage unit boundaries #451

Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -137,9 +137,13 @@ long fieldSize(Cursor c) {
return c.isBitField() ? c.getBitFieldWidth() : c.type().size() * 8;
}

//Todo: fixme
ValueLayout bitfield(ValueLayout v, List<MemoryLayout> sublayouts) {
return Utils.addContents(v, MemoryLayout.ofStruct(sublayouts.toArray(new MemoryLayout[0])));
ValueLayout bitfield(ValueLayout container, List<MemoryLayout> sublayouts) {
return Utils.addContents(container, MemoryLayout.ofStruct(sublayouts.toArray(new MemoryLayout[0])));
}

ValueLayout bitfield(long containerSize, List<MemoryLayout> sublayouts) {
return bitfield((ValueLayout)LayoutUtils.valueLayoutForSize(containerSize)
.layout().orElseThrow(() -> new IllegalStateException("Unsupported size: " + containerSize)), sublayouts);
}

long offsetOf(Type parent, Cursor c) {
@@ -136,56 +136,60 @@ private void handleBitfields() {
}
}

private String structName() {
String name = type.spelling();
return name.isEmpty()? "struct <anonymous>" : name;
}

private List<MemoryLayout> convertBitfields(List<MemoryLayout> layouts) {
long storageSize = storageSize(layouts);
long offset = 0L;
List<MemoryLayout> newFields = new ArrayList<>();
List<MemoryLayout> pendingFields = new ArrayList<>();
for (MemoryLayout l : layouts) {
MemoryLayout padding = null;
if (l.isPadding() && (offset + l.bitSize() > storageSize)) {
// split padding
long delta = storageSize - offset;
padding = MemoryLayout.ofPaddingBits(l.bitSize() - delta);
l = MemoryLayout.ofPaddingBits(delta);
}
offset += l.bitSize();
if (offset > MAX_STORAGE_SIZE) {
throw new IllegalStateException("Crossing storage unit boundaries");
}
pendingFields.add(l);
if (!pendingFields.isEmpty() && offset == storageSize) {
long storageSize = storageSize(offset);
if (!pendingFields.isEmpty() && storageSize != -1) {
//emit new
newFields.add(bitfield(
(ValueLayout)LayoutUtils.valueLayoutForSize(storageSize)
.layout().orElseThrow(() -> new IllegalStateException("Unsupported size: " + storageSize)),
pendingFields));
newFields.add(bitfield(storageSize, pendingFields));
pendingFields.clear();
offset = 0L;
} else if (offset > storageSize) {
throw new IllegalStateException("Crossing storage unit boundaries: " + structName());
}
if (padding != null) {
newFields.add(padding);
offset += padding.bitSize();
}
}
if (!pendingFields.isEmpty()) {
throw new IllegalStateException("Partially used storage unit: " + structName());
long storageSize = nextStorageSize(offset);
//emit new
newFields.add(bitfield(storageSize, pendingFields));
pendingFields.clear();
}
return newFields;
}

private long storageSize(List<MemoryLayout> layouts) {
long size = layouts.stream().mapToLong(MemoryLayout::bitSize).sum();
int[] sizes = { 64, 32, 16, 8 };
for (int s : sizes) {
if (size % s == 0) {
static int[] STORAGE_SIZES = { 64, 32, 16, 8 };
static int[] ALIGN_SIZES = { 8, 16, 32, 64 };
static int MAX_STORAGE_SIZE = 64;

private long storageSize(long size) {
// offset should be < MAX_STORAGE_SIZE
for (int s : STORAGE_SIZES) {
if (size == s) {
return s;
}
}
throw new IllegalStateException("Cannot infer storage size:" + structName());
return -1;
}

private long nextStorageSize(long size) {
// offset should be < MAX_STORAGE_SIZE
for (int s : ALIGN_SIZES) {
long alignedSize = alignUp(size, s);
long storageSize = storageSize(alignedSize);
if (storageSize != -1) {
return storageSize;
}
}
return -1;
}

private static long alignUp(long n, long alignment) {
return (n + alignment - 1) & -alignment;
}
}
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

import java.nio.file.Path;
import org.testng.annotations.Test;
import jdk.incubator.foreign.MemorySegment;
import static org.testng.Assert.assertNotNull;

/*
* @test
* @library .. /test/lib
* @modules jdk.incubator.jextract
* @build JextractToolRunner
* @bug 8260929
* @summary jextract crashes with Crossing storage unit boundaries
* @run testng/othervm -Dforeign.restricted=permit Test8261578
*/
public class Test8261578 extends JextractToolRunner {
@Test
public void test1() {
Path outputPath = getOutputFilePath("output_1");
Path headerFile = getInputFilePath("test8261578_1.h");
run("-d", outputPath.toString(), headerFile.toString()).checkSuccess();
try(Loader loader = classLoader(outputPath)) {
Class<?> ndpi_class = loader.loadClass("test8261578_1_h$ndpi_flow_tcp_struct");
assertNotNull(ndpi_class);

checkMethod(ndpi_class, "gnutella_msg_id$slice", MemorySegment.class, MemorySegment.class);
} finally {
deleteDir(outputPath);
}
}

@Test
public void test2() {
Path outputPath = getOutputFilePath("output_2");
Path headerFile = getInputFilePath("test8261578_2.h");
run("-d", outputPath.toString(), headerFile.toString()).checkSuccess();
try(Loader loader = classLoader(outputPath)) {
Class<?> foo_class = loader.loadClass("test8261578_2_h$foo");
assertNotNull(foo_class);

checkMethod(foo_class, "clear_color$slice", MemorySegment.class, MemorySegment.class);
checkMethod(foo_class, "clear_z$get", int.class, MemorySegment.class);
checkMethod(foo_class, "clear_z$set", void.class, MemorySegment.class, int.class);
checkMethod(foo_class, "clear_s$get", byte.class, MemorySegment.class);
checkMethod(foo_class, "clear_s$set", void.class, MemorySegment.class, byte.class);
} finally {
deleteDir(outputPath);
}
}

@Test
public void test3() {
Path outputPath = getOutputFilePath("output_3");
Path headerFile = getInputFilePath("test8261578_3.h");
run("-d", outputPath.toString(), headerFile.toString()).checkSuccess();
try(Loader loader = classLoader(outputPath)) {
Class<?> plugin_class = loader.loadClass("test8261578_3_h$PluginCodec_H323AudioG7231AnnexC");
assertNotNull(plugin_class);

checkMethod(plugin_class, "maxAl_sduAudioFrames$get", byte.class, MemorySegment.class);
checkMethod(plugin_class, "maxAl_sduAudioFrames$set", void.class, MemorySegment.class, byte.class);
} finally {
deleteDir(outputPath);
}
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

struct ndpi_flow_tcp_struct {
char gnutella_msg_id[3];
int irc_3a_counter:3;
int irc_stage2:5;
int irc_direction:2;
int irc_0x1000_full:1;
int soulseek_stage:2;
int filetopia_stage:2;
int tds_stage:3;
};
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

struct foo {
int clear_color[2];
int clear_z;
char clear_s;
int pad:24;
};
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

struct PluginCodec_H323AudioG7231AnnexC {
unsigned char maxAl_sduAudioFrames;
int silenceSuppression:1;
int highRateMode0:6; // INTEGER (27..78), -- units octets
int highRateMode1:6; // INTEGER (27..78), -- units octets
int lowRateMode0:6; // INTEGER (23..66), -- units octets
int lowRateMode1:6; // INTEGER (23..66), -- units octets
int sidMode0:4; // INTEGER (6..17), -- units octets
int sidMode1:4; // INTEGER (6..17), -- units octets
};