How to use ASM Opcodes.ACC_SYNTHETIC - bytecode

I am testing ACC_SYNTHETIC on a method by using ASM. The follows is my code
public static void generateMethodBean() throws IOException {
System.out.println("11111");
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "cn/curious/asm/Bean", null, "java/lang/Object", null);
MethodVisitor m0Visitor = cw.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, "lambda$main$1", "()V", null, null);
m0Visitor.visitCode();
m0Visitor.visitInsn(Opcodes.RETURN);
m0Visitor.visitMaxs(0, 0);
m0Visitor.visitEnd();
cw.visitEnd();
byte[] buffer = cw.toByteArray();
// StringWriter stringWriter = new StringWriter();
// PrintWriter printWriter = new PrintWriter(stringWriter);
// CheckClassAdapter.verify(new ClassReader(buffer), true, printWriter);
// System.out.println(printWriter.toString());
File file = new File(FILE_PATH_PREFIX + File.separator + "Bean2.class");
FileUtils.writeByteArrayToFile(file, buffer);
}
But the result class file has nothing.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package cn.curious.asm;
public class Bean {
}
I feel confusion about ACC_SYNTHETIC, how to use it correctly?
Update
Here is the javap output. The -p make it work.
javap -v -l -s -p Bean.class
Classfile /Users/Documents/work/idea_workspace/asmtest/src/main/java/cn/curious/asm/Bean.class
Last modified 2020-3-5; size 127 bytes
MD5 checksum 7367bcf65d9a32a72e4261101d3697cc
public class cn.curious.asm.Bean
minor version: 0
major version: 52
flags: ACC_PUBLIC
Constant pool:
#1 = Utf8 cn/curious/asm/Bean
#2 = Class #1 // cn/curious/asm/Bean
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 lambda$main$1
#6 = Utf8 ()V
#7 = Utf8 Code
{
private static void lambda$main$1();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=0, locals=0, args_size=0
0: return
}

Thats the idea behind synthetic methods, these are methods generated by compiler, so decompilers often skip it by default, as by definition they should not be needed in source code.
Like java specification states that
A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or
implicitly in source code, unless the emitted construct is a class
initialization method (JVMS §2.9).
And jvm one:
The ACC_SYNTHETIC flag indicates that this method was generated by a
compiler and does not appear in source code [with some exceptions]
Try to use javap -verbose -private -s -classpath yourJar.jar my.Class (or just directly to class filed) instead, it should list all your methods. Or just generate second normal method that will invoke this synthetic method and check if you can run it. Or just use reflections and getDeclaredMethods method to get all declared methods, including synthetic ones.

Related

Converting StreamListener with headers to Functional Model

Because #EnableBinding and #StreamListener are deprecated, I need to migrate existing code to the new model, however I could not find any information on whether the argument mapping available in Spring Cloud Stream is still supported and/or any clean workarounds.
My original method:
#StreamListener("mysource)
public void processMessage(byte[] rawMessage, #Header(required = false, value = KafkaHeaders.RECEIVED_MESSAGE_KEY) byte[] rawKey) {
processMessage(rawMessage, rawKey);
}
I managed to convert this to work as follows:
#Bean(name = "mysource")
public Consumer<Message<?>> mySource() {
return message -> {
byte[] rawMessage = message.getPayload().toString().getBytes();
byte[] rawKey = (byte[]) message.getHeaders().get("kafka_receivedMessageKey");
processMessage(rawMessage, rawKey);
};
}
However, what I would prefer is one that maximizes framework support with respect to argument mapping and/or automatic type conversions.
I attempted:
#Bean(name = "mysource")
public BiConsumer<Message<byte[]>, MessageHeaders> mySource() {
return (message, headers) -> {
byte[] rawMessage = message.getPayload();
byte[] rawKey = (byte[]) headers.get("kafka_receivedMessageKey");
processMessage(rawMessage, rawKey);
};
}
But this gives an error at startup: FunctionConfiguration$FunctionBindingRegistrar.afterPropertiesSet - The function definition 'mysource' is not valid. The referenced function bean or one of its components does not exist
I'm also aware that along with Supplier and Consumer, Function is also available, but I'm not sure how to use a Function in this case instead of a BiConsumer or if it's possible, so looking for examples on how to do this type of migration seamlessly and elegantly with respecting to consuming and producing messages plus headers from/to Kafka.

InvalidProtocolBufferException in Java client when deserializing protobuf data from C++ server

I have a protobuf message like this:
message Update {
Path path = 1; // The path (key) for the update.
Value value = 2 [deprecated=true]; // The value (value) for the update.
TypedValue val = 3; // The explicitly typed update value.
}
// TypedValue is used to encode a value being sent between the client and
// target (originated by either entity).
message TypedValue {
oneof value {
string string_val = 1; // String value.
int64 int_val = 2; // Integer
....
google.protobuf.Any any_val = 9; // protobuf.Any encoded bytes.
....
}
}
On the server side (C++), we are setting this field as follows (LLDP is the outer class and Interfaces is inside that):
openconfig_lldp::Lldp out;
GetLldpProto(&out);
update->mutable_val()->mutable_any_val()->PackFrom(out.interfaces());
On the client side (Java), we are extracting this field like this:
OpenconfigLldp.Lldp.Interfaces interfaces = update.getVal().getAnyVal().unpack(OpenconfigLldp.Lldp.Interfaces.class);
This is throwing a InvalidProtocolBufferException exception. When I dump the "update" in my Java client, I see this:
path {
elem {
name: "lldp"
}
elem {
name: "interfaces"
}
}
val {
any_val {
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
value: "\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/1\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/2\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/3\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n\212\207\237\334\v\374\001\022\371\001\262\211\267l\031\342\367\304\260\002\v\n\tEth 1/1/4\242\340\247\230\017\002\b\001\352\316\234\250\017\324\001\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh1\342\253\214\353\001\v\n\tEth 1/1/1\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh2\342\253\214\353\001\v\n\tEth 1/1/2\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh3\342\253\214\353\001\v\n\tEth 1/1/3\242\364\301\261\a\002\b\n\262\217\304\272\017/\022-\302\340\317\247\001\'\202\225\377\302\001\b\n\006Neigh4\342\253\214\353\001\v\n\tEth 1/1/4\242\364\301\261\a\002\b\n"
}
}
The type_url seems correct to me. What am I doing wrong here?
Thanks for your time.
EDIT #1:
I looked at the exception string. It is "Type of the Any message does not match the given class."
The same proto file is used for C++ and Java, but I see "openconfig_lldp.Lldp.Interfaces" in C++, where as, it is "OpenconfigLldp.Lldp.Interfaces" in Java. Need to find out why..
EDIT #2:
The same .proto file is used. In this case, it is:
openconfig_lldp.proto
---------------------
syntax = "proto3";
package openconfig.openconfig_lldp;
message Lldp {
message Config {
....
....
}
....
....
}
In case of Java, I see the parent class as OpenconfigLldp in a package called openconfig_lldp.
package openconfig.openconfig_lldp;
public final class OpenconfigLldp {
private OpenconfigLldp() {}
....
....
/**
* Protobuf type {#code openconfig.openconfig_lldp.Lldp}
*/
public static final class Lldp extends com.google.protobuf.GeneratedMessageV3 implements
// ##protoc_insertion_point(message_implements:openconfig.openconfig_lldp.Lldp)
....
....
}
In C++, I don't see any class called "OpenconfigLldp" generated. Instead it is just "Lldp"
So, the type_url in the Any.protobuf is a mismatch. C++ side puts it as
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
While in the Java side I use:
OpenconfigLldp.Lldp.Interfaces interfaces = update.getVal().getAnyVal().unpack(OpenconfigLldp.Lldp.Interfaces.class);
Anyone has thoughts on why there is a wrapper class in Java protoc output?
EDIT #3
Apparently looks like it is because of the "outer_class_name". In the Java code, I have an outer class "OpenconfigLldp".
The type_url format is:
type.googleapis.com/packagename.messagename
So, C++ code sets this to openconfig_lldp.Lldp.Interfaces.
But, this maps to OpenconfigLldp.Lldp.Interfaces in Java.
How could I work around this?
FINAL EDIT and FINAL QUESTION
After some digging around, this is what I found out.
By default, type_url is:
type_url: "type.googleapis.com/openconfig_lldp.Lldp.Interfaces"
On the Java side, I looked at the Any implementation. It tries to compare this with:
openconfig.openconfig_lldp.Lldp.Interfaces
I found this out by printing:
Lldp.Interfaces defaultInstance = (Lldp.Interfaces)Internal.getDefaultInstance(Lldp.Interfaces.class);
logger.info("full descriptor name: " + defaultInstance.getDescriptorForType().getFullName());
So, I hacked the C++ side to send:
update->mutable_val()->mutable_any_val()->set_type_url(std::string("type.googleapis.com/openconfig.openconfig_lldp.Lldp.Interfaces"));
So, I think I know what is happening here!
Thanks for reading through all the edits.
I am not sure if I understand correctly what's going wrong -- ideally the qualified names would be in protocol buffer namespaces -- language specific mappings shouldn't matter.
If the question is still open, I'd recommend to move the core of it to the top, preserving the edits as "what I have done so far".
Perhaps this is some kind of bug that could be worked around with on of these options:
java_multiple_files
java_outer_classname
More details about these options can be found here:
https://developers.google.com/protocol-buffers/docs/proto3

JDK8 type inference issue

I'm trying to run the following code which is compiled fine under JDK8 thanks to type inference:
public static <A,B> B convert(A a) {
return (B) new CB();
}
public static void main(String[] args) {
CA a = new CA();
CB b = convert(a); //this runs fine
List<CB> bl = Arrays.asList(b); //this also runs fine
List<CB> bl1 = Arrays.asList(convert(a)); //ClassCastException here
}
However, running this throws ClassCastException: CB cannot be cast to [Ljava.lang.Object, but the CB b = convert(a) works fine.
Any idea why?
Whenever you create a generic method with a signature that promises to return whatever the caller wishes, you are asking for trouble. You should have got an “unchecked” warning from the compiler which basically means: unexpected ClassCastExceptions may occur.
You expect the compiler to infer
List<CB> bl1 = Arrays.asList(YourClass.<CA,CB>convert(a));
whereas the compiler actually inferred
List<CB> bl1 = Arrays.asList(YourClass.<CA,CB[]>convert(a));
as far as I know, because it prefers method invocations not requiring a varargs packaging (which is compatible with pre-varargs code).
This fails because your convert method does not return the expected array type.

Reading objects from memory with MDbgEng

I wanted to help out #mark in a question where he is asking for an API to dump many objects from a .NET crash dump file.
So I wrote the following code using mdbgeng, but unfortunately it fails with a NotImplementedException when trying to enumerate the objects in memory.
using System;
using System.Runtime.InteropServices;
using Microsoft.Samples.Debugging.CorDebug;
using Microsoft.Samples.Debugging.CorDebug.Utility;
using Microsoft.Samples.Debugging.MdbgEngine;
using Microsoft.Samples.Debugging.Native;
namespace DumpHeapFromDotNet
{
class Program
{
static void Main(string[] args)
{
var libraryProvider = new LibraryProvider();
var dumpReader = new DumpReader(args[0]);
var dataTarget = new DumpDataTarget(dumpReader);
foreach (var module in dumpReader.EnumerateModules())
{
var clrDebugging = new CLRDebugging();
Version actualVersion;
ClrDebuggingProcessFlags flags;
CorProcess proc;
var hr = (HResult) clrDebugging.TryOpenVirtualProcess(module.BaseAddress, dataTarget, libraryProvider,
new Version(4, 6, int.MaxValue, int.MaxValue), out actualVersion, out flags, out proc);
if (hr < 0)
{
switch (hr)
{
case HResult.CORDBG_E_NOT_CLR:
Console.WriteLine(module.FullName + " is not a .NET module");
break;
case HResult.CORDBG_E_LIBRARY_PROVIDER_ERROR:
Console.WriteLine(module.FullName + " could not provide library");
break;
case HResult.CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL:
case HResult.CORDBG_E_UNSUPPORTED_FORWARD_COMPAT:
break;
default:
Marshal.ThrowExceptionForHR((int)hr);
break;
}
}
else
{
var objects = proc.Objects; // NotImplementedException
foreach (CorObjectValue o in objects)
{
// TODO: Write details of object to file here
}
}
}
Console.ReadLine();
}
}
}
The dump I was using is a .NET 4.6.1076.0 dump with full memory (you can pass a file name as an argument):
0:000> lm vm clr
[...]
ProductVersion: 4.6.1076.0
FileVersion: 4.6.1076.0 built by: NETFXREL3STAGE
0:000> .dumpdebug
----- User Mini Dump Analysis
MINIDUMP_HEADER:
Version A793 (61B1)
NumberOfStreams 11
Flags 1806
0002 MiniDumpWithFullMemory
0004 MiniDumpWithHandleData
0800 MiniDumpWithFullMemoryInfo
1000 MiniDumpWithThreadInfo
I doubt it has something to do with missing mscordacwks or similar, since I just created the dump on the same machine with the same .NET framework as I used for this sample.
Is it really not implemented yet, or am I doing something else wrong?
I'm currently messing with MDBG and I have tried to check the described behavior on real application, not on the dump. I received exatly the same not implemented exception. Looking for the documentation on MSDN I've found the confirmation, that this method is not implemented.

jcuda cuModuleLoad() cannot load file using the path of getClass().getResource().getPath()

I am trying to use cuModuleLoad() in JCuda to load a vectorAdd.ptx file from /src/main/resources. The code is as follows:
cuModuleLoad(module, getClass.getResource("vectorAdd.ptx").getPath())
But the cuModuleLoad() doesn't pick up this file. It only works when I pass in the absolute path of the ptx file. But I would like to have the ptx file shipped with compile jar files. Is there any way to accomplish this?
The cuModuleLoad function in JCuda is a direct mapping to the corresponding cuModuleLoad function in CUDA. It expects a file name as the second argument.
The problem is: cuModuleLoad can not load the PTX file, because the PTX file simply does not exist for CUDA! The PTX file is hidden inside the JAR file.
When you obtain a resource from a JAR file using someClass.getResource(), then it will point to the resource in the JAR file. When you do something like
System.out.println(getClass().getResource("vectorAdd.ptx").getPath());
and run this (as a JAR file), then you will see an output like this:
file:/U:/YourWorkspace/YourJarFile.jar!/vectorAdd.ptx
Note the .jar! part: This path is not a path to a real file, but only a path to a resource in the JAR.
In order to load the PTX file from a JAR, you have to read the PTX file from the JAR into a byte[] array on Java side, and then pass it to the cuModuleLoadData function of JCuda (which corresponds to the cuModuleLoadData function of CUDA).
Here is an example that loads the PTX data from a JAR file into a byte array, representing the zero-terminated string that can be passed to cuModuleLoadData:
import static jcuda.driver.JCudaDriver.cuCtxCreate;
import static jcuda.driver.JCudaDriver.cuDeviceGet;
import static jcuda.driver.JCudaDriver.cuInit;
import static jcuda.driver.JCudaDriver.cuModuleGetFunction;
import static jcuda.driver.JCudaDriver.cuModuleLoadData;
import static jcuda.runtime.JCuda.cudaDeviceReset;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import jcuda.driver.CUcontext;
import jcuda.driver.CUdevice;
import jcuda.driver.CUfunction;
import jcuda.driver.CUmodule;
import jcuda.driver.JCudaDriver;
public class JCudaPtxInJar
{
public static void main(String args[]) throws IOException
{
// Initialization
JCudaDriver.setExceptionsEnabled(true);
cuInit(0);
CUdevice device = new CUdevice();
cuDeviceGet(device, 0);
CUcontext context = new CUcontext();
cuCtxCreate(context, 0, device);
// Read the PTX data into a zero-terminated string byte array
byte ptxData[] = toZeroTerminatedStringByteArray(
JCudaPtxInJar.class.getResourceAsStream(
"JCudaVectorAddKernel.ptx"));
// Load the module data
CUmodule module = new CUmodule();
cuModuleLoadData(module, ptxData);
// Obtain a function pointer to the "add" function
// and print a simple test/debug message
CUfunction function = new CUfunction();
cuModuleGetFunction(function, module, "add");
System.out.println("Got function "+function);
cudaDeviceReset();
}
/**
* Read the contents of the given input stream, and return it
* as a byte array containing the ZERO-TERMINATED string data
* from the stream. The caller is responsible for closing the
* given stream.
*
* #param inputStream The input stream
* #return The ZERO-TERMINATED string byte array
* #throws IOException If an IO error occurs
*/
private static byte[] toZeroTerminatedStringByteArray(
InputStream inputStream) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[8192];
while (true)
{
int read = inputStream.read(buffer);
if (read == -1)
{
break;
}
baos.write(buffer, 0, read);
}
baos.write(0);
return baos.toByteArray();
}
}
Compiling this and packing it into a JAR (together with the /resources/JCudaVectorAddKernel.ptx PTX file, of course) will allow you to start the program and obtain the example function from the PTX in the JAR.

Resources