I use macros to allocate memory via JNI and then write to that memory.
#MacroAllocator
case class SomeCaseClass(a: Int, b: Int, c: Int)
3 * INT.BYTES = 12, so it means I need to allocate 12 bytes of memory.
I wrote a buffer that stores offheap objects. and if i already get address of buffer i can reuse that address to write/read.
typedef struct {
uint8_t *buf;
size_t size;
} buf_t;
via jni i'm allocating memory (assume it's at compile time)
JNIEXPORT jlong JNICALL Java_some_package_com_1alloc(JNIEnv *env, jobject self, jint size) {
globalenv = env;
buf_t buf;
buf_alloc(&buf, (size_t) size);
jlong buf_addr = (jlong)buf.buf;
return buf_addr;
}
and then i'm trying to write something to that buf, it's okay too (compile time too)
JNIEXPORT void JNICALL Java_some_package_com_1write_1int(JNIEnv *env, jobject self, jint value, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*) buf_addr;
write_int_to_buf_at(buf, idx, value);
return;
}
and when everything is done, i'm trying to read (runtime):
JNIEXPORT jint JNICALL Java_some_package_com_read_1int(JNIEnv *env, jobject self, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*)buf_addr;
int32_t value = read_int_in_buf_at(buf, (size_t) idx);
return value;
}
UPD: read_int_in_buf_at func impl
int32_t read_int_in_buf_at(uint8_t *buf, size_t idx) {
uint8_t b3 = buf[idx + 3];
uint8_t b2 = buf[idx + 2];
uint8_t b1 = buf[idx + 1];
uint8_t b0 = buf[idx];
return (b3 << 24) | ((b2 & 255) << 16) |
((b1 & 255) << 8) | (b0 & 255);
}
i get some weird results when trying to read: 0, 1234125360, -1342346458, etc.
Continuing from the comments, you have to keep in mind that Java_some_package_com_1alloc returns the address of allocated memory (buf.buf) NOT the buf_t struct itself.
This means your functions have to change accordingly:
JNIEXPORT void JNICALL Java_some_package_com_1write_1int(JNIEnv *env, jobject self, jint value, jint idx, jlong buf_addr) {
globalenv = env;
// The `jlong` value is the address of allocated memory
uint8_t *buf = (uint8_t*) buf_addr;
write_int_to_buf_at(buf, idx, value);
}
and the reader:
JNIEXPORT jint JNICALL Java_some_package_com_read_1int(JNIEnv *env, jobject self, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*) buf_addr;
int32_t value = read_int_in_buf_at(buf, (size_t) idx);
return value;
}
Related
I have unsigned char buffer in which I have data and I need to copy it to a jbyteArray so that I could return it in byte array format. This is my piece of code
C code:
JNIEXPORT jbyteArray JNICALL Java_hello1_recieve(JNIEnv *env, jobject object)
{
ssize_t bytes_read;
/* receive the message */
bytes_read = mq_receive(mq,buff, MAX_SIZE, NULL);
jbyteArray b[bytes_read];
CHECK(bytes_read >= 0);
buff[bytes_read] = '\0';
int i=0;
while(buff[i]!='\0')
{
b[i]=buff[i];
printf("%c\n",b[i]);
i++;
}
/* cleanup */
CHECK((mqd_t)-1 != mq_close(mq));
CHECK((mqd_t)-1 != mq_unlink(QUEUE_NAME));
return b;
}
here CHECK(x) is:
do{
if (!(x))
{
fprintf(stderr, "%s:%d: ", __func__, __LINE__);
perror(#x);
exit(-1);
}
} while (0)
And the code for java side is:
public class hello1 {
public native void sayHello() ;
public native byte[] recieve() ;
public static void main (String args[]) {
hello1 h = new hello1 () ;
h.sayHello () ;
System.out.println("connection open");
byte[] rdata= new byte[3];
rdata=h.recieve();
int i=0;
while( rdata[i] != '\0')
{
System.out.println( rdata [i]);
i++;
}
System.out.println("connection closed");
}
static {
System.loadLibrary ( "hello1" ) ;
}
}
but I am getting a java.lang.NullPointerException when I try to print rdata. Where is the problem?
Thanks
Update
this worked:-
jbyteArray b=(*env)->NewByteArray(env, bytes_read);
(*env)->SetByteArrayRegion(env, b, 0, bytes_read, (jbyte *)buff);
jbyteArray b=(*env)->NewByteArray(env, bytes_read);
(*env)->SetByteArrayRegion(env, b, 0, bytes_read, (jbyte *)buff);
// after cleanup
return b;
jbyteArray b[bytes_read];
This is not valid. You need to create this object with the JNI API, not via a local array declaration. It isn't an array in C code, it is a pointer to an object.
I have just started using visualgdb
#include <string.h>
#include <jni.h>
#include <stdio.h>
int s_ButtonPressCounter = 0;
jstring
Java_com_visualgdb_example_AndroidProject1_AndroidProject1_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char szBuf[512];
sprintf(szBuf, "You have pressed this huge button %d times", s_ButtonPressCounter++);
jstring str = (*env)->NewStringUTF(env, szBuf);
return str;
}
I have my intelissense show error log
Expression must have pointer type.
I tried to change it to env.NewStringUTF(szBuf) but the build comes to error.
Maybe, you should replace
jstring str = (*env)->NewStringUTF(env, szBuf);
with
jstring str = env->NewStringUTF(env, szBuf);
or with
jstring str = (*env).NewStringUTF(env, szBuf);
I have gotten this error when setting the -Xcheck:jni option, and calling my native method.
The error is :
FATAL ERROR in native method: Bad global or local ref passed to JNI
I shall paste the native method (C code) here, hope that anybody who knows what is wrong with this piece of code, will enlighten me. Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fns_data.h"
#include "fns_client.h"
#include "sockRW.h"
#include "/usr/local/include/jni.h"
#include "JNIiSearchLib.h"
#include "com_eds_wise_util_JNIiSearchLib.h"
JNIEXPORT jstring JNICALL
Java_com_eds_wise_util_JNIiSearchLib_jniFNSSearchClient (
JNIEnv *env, jobject obj, jstring jip_addr, jint jport_number,
jstring jfield, jstring jquery_str, jint jhitnum)
{
HitIds *hit_list = NULL;
hitListPktStruct *hitPkt = NULL;
int hit_number = 0;
int i = 0;
int fnsErrno = 0;
char *result_str = NULL;
jstring *rslt_str = NULL;
const char *cip_addr = NULL;
const char *cquery_str = NULL;
char errbuf[1024];
cip_addr = (*env)->GetStringUTFChars(env, jip_addr, 0);
if (cip_addr == NULL) {
return ((* env)->NewStringUTF (env, "Error: Cannot get IP address."));
}
cquery_str = (*env)->GetStringUTFChars(env, jquery_str, 0);
if (cquery_str == NULL) {
(*env)->ReleaseStringUTFChars (env, jip_addr, cip_addr);
(*env)->DeleteLocalRef(env, cip_addr);
return ((* env)->NewStringUTF (env, "Error: Cannot get query string."));
}
printf ("[Java_JNILib_jniFNSSearchClient] ipaddress[%s] portnumber[%d]"
" querystr[%s]\n\n", cip_addr, jport_number, cquery_str);
/* Search and get back the handler & total hits
*/
hit_list = fns_search_client0 (cip_addr, jport_number,
"PN", cquery_str, &hit_number);
/* Display total hits
*/
printf ("Total hits = %d\n", hit_number);
/* Enumerate every item in the result list and display them.
* The results are returned as a string to Java in the following manner:
*
* "[hitresult1|hitresult2|hitresult3|..|hitresultN]\0"
*
* where hitresultN = 94-byte record
*
* [+string94+|+string94]+stringTerminator
*/
printf ("malloc[%d]\n", (hit_number * 95) + 3);
result_str = malloc (((hit_number * 95)+3) * sizeof(char));
if (result_str == NULL) {
printf ("Out of memory, unable to malloc\n");
rslt_str = (* env)->NewStringUTF (env, "Error: Out of memory, unable to malloc");
if (hit_list) {
FREE_STRING (hit_list);
}
if (hitPkt) {
FREE_HITLIST_STRUCT (hitPkt);
}
(*env)->ReleaseStringUTFChars (env, jip_addr, cip_addr);
(*env)->ReleaseStringUTFChars (env, jquery_str, cquery_str);
(*env)->DeleteLocalRef(env, cip_addr);
(*env)->DeleteLocalRef(env, cquery_str);
fflush(stdout);
return (rslt_str);
}
sprintf (result_str, "[");
for (i = 0; i < hit_number; i++) {
strcat (result_str, hitPkt->docNameList[i]);
if (i != (hit_number - 1)) {
strcat (result_str, "|");
}
}
strcat (result_str, "]");
printf ("\n\nFNS search result:[From Library]\n");
printf ("%s\n\n",result_str);
/* free the handler
*/
if (hit_list) {
FREE_STRING (hit_list);
}
/* free the result lists
*/
if (hitPkt) {
FREE_HITLIST_STRUCT (hitPkt);
}
/* prepare stuff for Java
*/
rslt_str = (* env)->NewStringUTF (env, result_str);
/* free our memory
*/
if (result_str) {
free (result_str);
}
(*env)->ReleaseStringUTFChars (env, jip_addr, cip_addr);
(*env)->ReleaseStringUTFChars (env, jquery_str, cquery_str);
(*env)->DeleteLocalRef(env, cip_addr);
(*env)->DeleteLocalRef(env, cquery_str);
fflush(stdout);
return (rslt_str);
}
I wonder how this even compiles. jstring is a pointer type already, so yours
jstring *rslt_str = NULL;
is a pointer to pointer, and i wonder how the compiler can take it as retval for GetStringUTFChars and returning it from your native method altogether.
Not familiar with c++, can someone help me add cmd to the myStr array and pass it to the main() function, here is what I have so far:
JNIEXPORT void JNICALL Java_my_package_JNIActivity_callCmdLine(
JNIEnv *env, jobject obj, jstring cmd)
{
const char *nativeString = env->GetStringUTFChars(cmd, 0);
env->ReleaseStringUTFChars(cmd, nativeString);
char * myStr [] = {"v", nativeString};
//int main(int argc, char *argv[])
main(1, myStr);
}
Well, don't release it before you're finished with it.
char * nativeString;
{ const char * _nativeString = env->GetStringUTFChars(cmd, 0);
nativeString = strdup (_nativeString);
env->ReleaseStringUTFChars(cmd, _nativeString);
}
char * myStr [] = {"v", nativeString};
main(1, myStr);
free (nativeString);
Why not taking advantage of objects to garantee deletion is done automatically...?
class ConvertStringHelper
{
public:
ConvertStringHelper( JNIEnv *env, jstring value )
{
m_str = env->GetStringUTFChars(value, 0);
m_value = &value;
m_env = env;
}
~ConvertStringHelper()
{
m_env->ReleaseStringUTFChars( *m_value, m_str);
}
jstring* m_value;
const char *m_str;
JNIEnv *m_env;
};
Then:
ConvertStringHelper helper( env, cmd );
const char* nativeStr = helper.m_str;
// nativeStr is valid in helper's scope and memory will be cleanly released when exiting the scope!
HI All,
I was trying to overload new and delete to fix a memory leak problem in my project. But got stuck with some compilation error.
Currently this code is bit shabby
Here is my hdr file
#include <cstddef>
#include <iostream>
#include <list>
#include <stdarg.h>
#include <stdio.h>
using namespace std;
typedef unsigned int DWORD;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum);
char *OutputDebugString (const char *fmt, ...);
void RemoveTrack(DWORD addr);
void DumpUnfreed();
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW
void * operator new (unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
}
/*inline void * operator new(unsigned int size)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, _FILE_,_LINE_);
return(ptr);
}*/
void operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
}
#endif
char *OutputDebugString (const char *fmt, ...)
{
char *p = NULL;
size_t size = 1024;
int n = 0;
va_list ap;
if((p = (char*) malloc(size)) == NULL)
return NULL;
while(1) {
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
if(n > -1 && n < size)
return p;
/* failed: have to try again, alloc more mem. */
if(n > -1) /* glibc 2.1 */
size = n + 1;
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if((p = (char *)realloc (p, size)) == NULL)
return NULL;
}
}
typedef struct information {
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;
typedef list < ALLOC_INFO* > AllocList;
AllocList *allocList;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum)
{
ALLOC_INFO *info;
if(!allocList) {
//allocList = new AllocList;
allocList = (AllocList*)malloc (sizeof (AllocList));
}
//info = new(ALLOC_INFO);
info = (ALLOC_INFO*) malloc (sizeof (ALLOC_INFO));
info->address = addr;
strncpy(info->file, fname, 63);
info->line = lnum;
info->size = asize;
allocList->insert(allocList->begin(), info);
}
void RemoveTrack(DWORD addr)
{
AllocList::iterator i;
if(!allocList)
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++)
{
if((*i)->address == addr)
{
allocList->remove((*i));
break;
}
}
}
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString("%s",buf);
totalSize += (*i)->size;
}
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString("%s",buf);
sprintf(buf, "Total Unfreed: %d bytes\n", totalSize);
OutputDebugString("%s",buf);
}
And my main.cpp is
#include "mynew.h"
int main()
{
char *ptr = new char;
DumpUnfreed();
return 0;
}
When i try to compile i get the following error
[root#dhcppc0 new]# !g
g++ main.cpp -D_DEBUG
mynew.h:25: error: declaration of ‘operator new’ as non-function
main.cpp: In function ‘int main()’:
main.cpp:9: error: no matching function for call to ‘operator new(unsigned int, const char [9], int)’
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:84: note: candidates are: void* operator new(size_t)
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:88: note: void* operator new(size_t, const std::nothrow_t&)
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/new:94: note: void* operator new(size_t, void*)
I know there is some thing wrong with my #defines, but I am not sure what is wrong.
Can any one please bale me out of this
You've defined your new macro before your functions. Your code ends up looking like:
void *
operator new(__FILE__, __LINE__)(unsigned int size, const char *file, int line)
Which is obviously wrong. Your should move the macro definitions underneath the functions (or better is to keep those functions in a .cpp file you link with.) For what it's worth, new is a keyword and cannot be an identifier, so your program is, strictly speaking, ill-formed.
I recently posted my global memory operators framework. It might help you a bit.
the signature don't match it sould be void* operator new (size_t size).
overriding single object new signature is
static void * operator new(site_t size),
roni