Skip to content

Commit

Permalink
[java-interop, Java.Interop] Securely load native libs
Browse files Browse the repository at this point in the history
Fixes: #676

Context: https://liquid.microsoft.com/Web/Object/Read/ms.security/Requirements/Microsoft.Security.SystemsADM.10039#guide

The current security guidance is that the
[`System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute`][0]
attribute should be placed either on the assembly or on `[DllImport]`
methods to control and constrain where [`LoadLibraryEx()`][1] will look
for native libraries, in particular to *prevent* looking for native
libraries within e.g. the current working directory or `%PATH%` or any
other "attacker-controlled" location.

Update `Java.Interop.dll` and `Java.Runtime.Environment.dll` so that
the [`DllImportSearchPath`][2] values `AssemblyDirectory` and
`SafeDirectories` are used:

  * `AssemblyDirectory`: "include the directory that contains the
    assembly itself, and search that directory first."

  * `SafeDirectories`: "Include the application directory, the
    `%WinDir%\System32` directory, and user directories in the DLL
    search path.

Additionally, update `src/java-interop` so that instead of requiring
the use of [**dlopen**(3)] on Windows, the following new exports are
added to support loading native libraries and resolving symbols from
those native libraries:

	void*   java_interop_load_library (const char *path, unsigned int flags, char **error);
	void*   java_interop_get_symbol_address (void* library, const char *symbol, char **error);
	int     java_interop_close_library (void* library, char **error);

On Windows, `java_interop_load_library()` will use
[`LoadLibraryEx()`][4] to load libraries from a constrained set of
directories:

  * `LOAD_LIBRARY_SEARCH_APPLICATION_DIR`: "the application's
    installation directory is searched for the DLL and its dependencies"

  * `LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR`: "the directory that contains
    the DLL is temporarily added to the beginning of the list of
    directories that are searched for the DLL's dependencies."

  * `LOAD_LIBRARY_SEARCH_USER_DIRS`: "directories added using the
    `AddDllDirectory()` or the `SetDllDirectory()` function are searched
    for the DLL and its dependencies"

In order to simplify the introduction of
`java_interop_load_library()`, start *requiring* the presence of the
symbols `mono_thread_get_managed_id` and `mono_thread_get_name_utf8`.
These symbols have been present within Mono for ages at this point,
and requiring means we don't need to support `dlopen(NULL)` semantics.

Update the `@(ClInclude)` item group and `BuildMac` and related targets
so that we properly rebuild things when e.g. `java-interop-dlfcn.h`
changes, as would "normally" be expected.

Finally, the continued use of `MONO_API` and other macros causes
"weird" compiler issues when integrating with xamarin-android.
Replace `MONO_API`/etc. use with `JAVA_INTEROP_API`/etc. instead.

[0]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultdllimportsearchpathsattribute?view=netcore-3.1
[1]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa?redirectedfrom=MSDN
[2]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportsearchpath?view=netcore-3.1
[3]: https://linux.die.net/man/3/dlopen
[4]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa
  • Loading branch information
jonpryor committed Aug 20, 2020
1 parent 007b35b commit 4bfe49d
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 145 deletions.
2 changes: 2 additions & 0 deletions src/Java.Interop/Java.Interop/JniRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using System.Runtime.InteropServices;
using System.Threading;

[assembly: DefaultDllImportSearchPathsAttribute (DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]

namespace Java.Interop
{
delegate int DestroyJavaVMDelegate (IntPtr javavm);
Expand Down
2 changes: 2 additions & 0 deletions src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Runtime.InteropServices;
using System.Threading;

[assembly: DefaultDllImportSearchPathsAttribute (DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]

namespace Java.Interop {

struct JavaVMInitArgs {
Expand Down
40 changes: 4 additions & 36 deletions src/java-interop/java-interop-gc-bridge-mono.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#include "logger.h"
#endif /* !defined (ANDROID) */

#include <dlfcn.h>

#if defined (ANDROID) || defined (XAMARIN_ANDROID_DYLIB_MONO)
using namespace xamarin::android;
#endif
Expand Down Expand Up @@ -76,23 +74,6 @@ struct JavaInteropGCBridge {
int gref_cleanup, lref_cleanup;
};

typedef char* (*MonoThreadGetNameUtf8)(MonoThread*);
typedef int32_t (*MonoThreadGetManagedId)(MonoThread*);

static MonoThreadGetManagedId _mono_thread_get_managed_id;
static MonoThreadGetNameUtf8 _mono_thread_get_name_utf8;

static void
lookup_optional_mono_thread_functions (void)
{
void *h = dlopen (NULL, RTLD_LAZY);
if (!h)
return;

_mono_thread_get_managed_id = reinterpret_cast<MonoThreadGetManagedId>(dlsym (h, "mono_thread_get_managed_id"));
_mono_thread_get_name_utf8 = reinterpret_cast<MonoThreadGetNameUtf8>(dlsym (h, "mono_thread_get_name_utf8"));
}

static jobject
lref_to_gref (JNIEnv *env, jobject lref)
{
Expand Down Expand Up @@ -275,8 +256,6 @@ java_interop_gc_bridge_new (JavaVM *jvm)
}
#endif /* defined (XAMARIN_ANDROID_DYLIB_MONO) */

lookup_optional_mono_thread_functions ();

JavaInteropGCBridge bridge = {0};

bridge.jvm = jvm;
Expand Down Expand Up @@ -1237,26 +1216,15 @@ gc_is_bridge_object (MonoObject *object)
static char *
get_thread_name (void)
{
if (_mono_thread_get_name_utf8) {
MonoThread *thread = mono_thread_current ();
return _mono_thread_get_name_utf8 (thread);
}
return strdup ("finalizer");
MonoThread *thread = mono_thread_current ();
return mono_thread_get_name_utf8 (thread);
}

static int64_t
get_thread_id (void)
{
if (_mono_thread_get_managed_id) {
MonoThread *thread = mono_thread_current ();
return _mono_thread_get_managed_id (thread);
}
#if __linux__
int64_t tid = (int64_t)((pid_t)syscall(SYS_gettid));
#else
int64_t tid = (int64_t) pthread_self ();
#endif
return tid;
MonoThread *thread = mono_thread_current ();
return mono_thread_get_managed_id (thread);
}

static void
Expand Down
54 changes: 27 additions & 27 deletions src/java-interop/java-interop-gc-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,41 @@ struct JavaInterop_System_RuntimeTypeHandle {
void *value;
};

MONO_API JavaInteropGCBridge *java_interop_gc_bridge_get_current (void);
MONO_API int java_interop_gc_bridge_set_current_once (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API JavaInteropGCBridge *java_interop_gc_bridge_get_current (void);
JAVA_INTEROP_API int java_interop_gc_bridge_set_current_once (JavaInteropGCBridge *bridge);

MONO_API JavaInteropGCBridge *java_interop_gc_bridge_new (JavaVM *jvm);
MONO_API int java_interop_gc_bridge_free (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API JavaInteropGCBridge *java_interop_gc_bridge_new (JavaVM *jvm);
JAVA_INTEROP_API int java_interop_gc_bridge_free (JavaInteropGCBridge *bridge);

MONO_API int java_interop_gc_bridge_register_hooks (JavaInteropGCBridge *bridge, int weak_ref_kind);
MONO_API int java_interop_gc_bridge_wait_for_bridge_processing (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_register_hooks (JavaInteropGCBridge *bridge, int weak_ref_kind);
JAVA_INTEROP_API int java_interop_gc_bridge_wait_for_bridge_processing (JavaInteropGCBridge *bridge);

MONO_API int java_interop_gc_bridge_add_current_app_domain (JavaInteropGCBridge *bridge);
MONO_API int java_interop_gc_bridge_remove_current_app_domain (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_add_current_app_domain (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_remove_current_app_domain (JavaInteropGCBridge *bridge);

MONO_API int java_interop_gc_bridge_set_bridge_processing_field (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle, char *field_name);
MONO_API int java_interop_gc_bridge_register_bridgeable_type (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle);
MONO_API int java_interop_gc_bridge_enable (JavaInteropGCBridge *bridge, int enable);
JAVA_INTEROP_API int java_interop_gc_bridge_set_bridge_processing_field (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle, char *field_name);
JAVA_INTEROP_API int java_interop_gc_bridge_register_bridgeable_type (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle);
JAVA_INTEROP_API int java_interop_gc_bridge_enable (JavaInteropGCBridge *bridge, int enable);

MONO_API int java_interop_gc_bridge_get_gref_count (JavaInteropGCBridge *bridge);
MONO_API int java_interop_gc_bridge_get_weak_gref_count (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_get_gref_count (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_get_weak_gref_count (JavaInteropGCBridge *bridge);

MONO_API int java_interop_gc_bridge_lref_set_log_file (JavaInteropGCBridge *bridge, const char *gref_log_file);
MONO_API FILE* java_interop_gc_bridge_lref_get_log_file (JavaInteropGCBridge *bridge);
MONO_API int java_interop_gc_bridge_lref_set_log_level (JavaInteropGCBridge *bridge, int level);
MONO_API void java_interop_gc_bridge_lref_log_message (JavaInteropGCBridge *bridge, int level, const char *message);
MONO_API void java_interop_gc_bridge_lref_log_new (JavaInteropGCBridge *bridge, int lref_count, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
MONO_API void java_interop_gc_bridge_lref_log_delete (JavaInteropGCBridge *bridge, int lref_count, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API int java_interop_gc_bridge_lref_set_log_file (JavaInteropGCBridge *bridge, const char *gref_log_file);
JAVA_INTEROP_API FILE* java_interop_gc_bridge_lref_get_log_file (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_lref_set_log_level (JavaInteropGCBridge *bridge, int level);
JAVA_INTEROP_API void java_interop_gc_bridge_lref_log_message (JavaInteropGCBridge *bridge, int level, const char *message);
JAVA_INTEROP_API void java_interop_gc_bridge_lref_log_new (JavaInteropGCBridge *bridge, int lref_count, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API void java_interop_gc_bridge_lref_log_delete (JavaInteropGCBridge *bridge, int lref_count, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);

MONO_API int java_interop_gc_bridge_gref_set_log_file (JavaInteropGCBridge *bridge, const char *gref_log_file);
MONO_API FILE* java_interop_gc_bridge_gref_get_log_file (JavaInteropGCBridge *bridge);
MONO_API int java_interop_gc_bridge_gref_set_log_level (JavaInteropGCBridge *bridge, int level);
MONO_API void java_interop_gc_bridge_gref_log_message (JavaInteropGCBridge *bridge, int level, const char *message);
MONO_API int java_interop_gc_bridge_gref_log_new (JavaInteropGCBridge *bridge, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
MONO_API int java_interop_gc_bridge_gref_log_delete (JavaInteropGCBridge *bridge, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API int java_interop_gc_bridge_gref_set_log_file (JavaInteropGCBridge *bridge, const char *gref_log_file);
JAVA_INTEROP_API FILE* java_interop_gc_bridge_gref_get_log_file (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_gref_set_log_level (JavaInteropGCBridge *bridge, int level);
JAVA_INTEROP_API void java_interop_gc_bridge_gref_log_message (JavaInteropGCBridge *bridge, int level, const char *message);
JAVA_INTEROP_API int java_interop_gc_bridge_gref_log_new (JavaInteropGCBridge *bridge, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API int java_interop_gc_bridge_gref_log_delete (JavaInteropGCBridge *bridge, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);

MONO_API int java_interop_gc_bridge_weak_gref_log_new (JavaInteropGCBridge *bridge, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
MONO_API int java_interop_gc_bridge_weak_gref_log_delete (JavaInteropGCBridge *bridge, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API int java_interop_gc_bridge_weak_gref_log_new (JavaInteropGCBridge *bridge, jobject curHandle, char curType, jobject newHandle, char newType, const char *thread_name, int64_t thread_id, const char *from);
JAVA_INTEROP_API int java_interop_gc_bridge_weak_gref_log_delete (JavaInteropGCBridge *bridge, jobject handle, char type, const char *thread_name, int64_t thread_id, const char *from);

JAVA_INTEROP_END_DECLS

Expand Down
17 changes: 11 additions & 6 deletions src/java-interop/java-interop-jvm.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <stdlib.h>
#include <dlfcn.h>

#include "java-interop-jvm.h"
#include "java-interop-dlfcn.h"
#include "java-interop-logger.h"
#include "java-interop-util.h"

Expand Down Expand Up @@ -33,11 +33,13 @@ java_interop_jvm_load_with_error_message (const char *path, char **error_message
return JAVA_INTEROP_JVM_FAILED_OOM;
}

jvm->dl_handle = dlopen (path, RTLD_LAZY);
char *error = nullptr;
jvm->dl_handle = java_interop_load_library (path, 0, &error);
if (!jvm->dl_handle) {
if (error_message) {
*error_message = java_interop_strdup (dlerror ());
*error_message = java_interop_strdup (error);
}
free (error);
free (jvm);
jvm = NULL;
return JAVA_INTEROP_JVM_FAILED_NOT_LOADED;
Expand All @@ -46,10 +48,13 @@ java_interop_jvm_load_with_error_message (const char *path, char **error_message
int symbols_missing = 0;

#define LOAD_SYMBOL_CAST(symbol, Type) do { \
jvm->symbol = reinterpret_cast<Type>(dlsym (jvm->dl_handle, #symbol)); \
error = nullptr; \
jvm->symbol = reinterpret_cast<Type>(java_interop_get_symbol_address (jvm->dl_handle, #symbol, &error)); \
if (!jvm->symbol) { \
log_error (LOG_DEFAULT, "Failed to load JVM symbol: %s", #symbol); \
log_error (LOG_DEFAULT, "Failed to load JVM symbol: %s: %s", #symbol, error); \
symbols_missing = 1; \
free (error); \
error = nullptr; \
} \
} while (0)
#define LOAD_SYMBOL(symbol) LOAD_SYMBOL_CAST(symbol, java_interop_ ## symbol ## _fptr)
Expand All @@ -61,7 +66,7 @@ java_interop_jvm_load_with_error_message (const char *path, char **error_message
#undef LOAD_SYMBOL

if (symbols_missing) {
dlclose (jvm->dl_handle);
java_interop_close_library (jvm->dl_handle, nullptr);
free (jvm);
jvm = NULL;
return JAVA_INTEROP_JVM_FAILED_SYMBOL_MISSING;
Expand Down
8 changes: 4 additions & 4 deletions src/java-interop/java-interop-jvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ JAVA_INTEROP_BEGIN_DECLS
#define JAVA_INTEROP_JVM_FAILED_OOM (JAVA_INTEROP_JVM_FAILED-3)
#define JAVA_INTEROP_JVM_FAILED_SYMBOL_MISSING (JAVA_INTEROP_JVM_FAILED-4)

MONO_API int java_interop_jvm_load (const char *path);
MONO_API int java_interop_jvm_load_with_error_message (const char *path, char **error);
MONO_API int java_interop_jvm_create (JavaVM **p_vm, void **p_env, void *vm_args);
MONO_API int java_interop_jvm_list (JavaVM **vmBuf, int bufLen, int *nVMs);
JAVA_INTEROP_API int java_interop_jvm_load (const char *path);
JAVA_INTEROP_API int java_interop_jvm_load_with_error_message (const char *path, char **error);
JAVA_INTEROP_API int java_interop_jvm_create (JavaVM **p_vm, void **p_env, void *vm_args);
JAVA_INTEROP_API int java_interop_jvm_list (JavaVM **vmBuf, int bufLen, int *nVMs);

JAVA_INTEROP_END_DECLS

Expand Down
44 changes: 7 additions & 37 deletions src/java-interop/java-interop-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,13 @@

#include "java-interop.h"

#if defined (XAMARIN_ANDROID_DYLIB_MONO)

#include "dylib-mono.h"
#include "monodroid-glue.h"

#define mono_class_from_mono_type (monodroid_get_dylib ()->class_from_mono_type)
#define mono_class_from_name (monodroid_get_dylib ()->class_from_name)
#define mono_class_get_field_from_name (monodroid_get_dylib ()->class_get_field_from_name)
#define mono_class_get_name (monodroid_get_dylib ()->class_get_name)
#define mono_class_get_namespace (monodroid_get_dylib ()->class_get_namespace)
#define mono_class_is_subclass_of (monodroid_get_dylib ()->class_is_subclass_of)
#define mono_class_vtable (monodroid_get_dylib ()->class_vtable)
#define mono_domain_get (monodroid_get_dylib ()->domain_get)
#define mono_field_get_value (monodroid_get_dylib ()->field_get_value)
#define mono_field_set_value (monodroid_get_dylib ()->field_set_value)
#define mono_field_static_set_value (monodroid_get_dylib ()->field_static_set_value)
#define mono_object_get_class (monodroid_get_dylib ()->object_get_class)
#define mono_thread_attach (monodroid_get_dylib ()->thread_attach)
#define mono_thread_current (monodroid_get_dylib ()->thread_current)
#define mono_gc_register_bridge_callbacks (monodroid_get_dylib ()->gc_register_bridge_callbacks)
#define mono_gc_wait_for_bridge_processing (monodroid_get_dylib ()->gc_wait_for_bridge_processing)

#else /* !defined (XAMARIN_ANDROID_DYLIB_MONO) */

#undef MONO_API_EXPORT
#undef MONO_API_IMPORT
#undef MONO_API

#include <mono/metadata/assembly.h>
#include <mono/metadata/class.h>
#include <mono/metadata/object.h>
#include <mono/metadata/sgen-bridge.h>
#include <mono/metadata/threads.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-dl-fallback.h>

#endif /* !defined (XAMARIN_ANDROID_DYLIB_MONO) */
#include <mono/metadata/assembly.h>
#include <mono/metadata/class.h>
#include <mono/metadata/object.h>
#include <mono/metadata/sgen-bridge.h>
#include <mono/metadata/threads.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-dl-fallback.h>

JAVA_INTEROP_BEGIN_DECLS

Expand Down
4 changes: 3 additions & 1 deletion src/java-interop/java-interop-util.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __JAVA_INTEROP_UTIL_H__
#define __JAVA_INTEROP_UTIL_H__

#include <cstdlib>

#ifdef WINDOWS
/* Those two conversion functions are only properly implemented on Windows
* because that's the only place where they should be useful.
Expand Down Expand Up @@ -44,7 +46,7 @@ _assert_valid_pointer (void *p, size_t size)
}

log_fatal (LOG_DEFAULT, "Out of memory!");
exit (FATAL_EXIT_OUT_OF_MEMORY);
std::exit (FATAL_EXIT_OUT_OF_MEMORY);
}

return p;
Expand Down
7 changes: 6 additions & 1 deletion src/java-interop/java-interop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputPath>$(ToolOutputFullPath)</OutputPath>
<JNIEnvGenPath>$(BuildToolOutputFullPath)</JNIEnvGenPath>
<OutputName>java-interop</OutputName>
<DefineSymbols>JI_DLL_EXPORT MONODEVELOP MONO_DLL_EXPORT</DefineSymbols>
<DefineSymbols>JI_DLL_EXPORT MONODEVELOP JAVA_INTEROP_DLL_EXPORT</DefineSymbols>
<SourceDirectory>.</SourceDirectory>
</PropertyGroup>

Expand All @@ -18,8 +18,12 @@

<ItemGroup>
<ClInclude Include="java-interop.h" />
<ClInclude Include="java-interop-dlfcn.h" />
<ClInclude Include="java-interop-gc-bridge.h" />
<ClInclude Include="java-interop-jvm.h" />
<ClInclude Include="java-interop-logger.h" />
<ClInclude Include="java-interop-mono.h" />
<ClInclude Include="java-interop-util.h" />
</ItemGroup>

<PropertyGroup>
Expand All @@ -37,6 +41,7 @@
<ItemGroup>
<ClCompile Include="jni.c" />
<ClCompile Include="java-interop.cc" />
<ClCompile Include="java-interop-dlfcn.cc" />
<ClCompile Include="java-interop-jvm.cc" />
<ClCompile Include="java-interop-logger.cc" />
<ClCompile Include="java-interop-mono.cc" />
Expand Down
26 changes: 13 additions & 13 deletions src/java-interop/java-interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@

#if defined(_MSC_VER)

#define MONO_API_EXPORT __declspec(dllexport)
#define MONO_API_IMPORT __declspec(dllimport)
#define JAVA_INTEROP_API_EXPORT __declspec(dllexport)
#define JAVA_INTEROP_API_IMPORT __declspec(dllimport)

#else /* defined(_MSC_VER */

#ifdef __GNUC__
#define MONO_API_EXPORT __attribute__ ((visibility ("default")))
#define JAVA_INTEROP_API_EXPORT __attribute__ ((visibility ("default")))
#else
#define MONO_API_EXPORT
#define JAVA_INTEROP_API_EXPORT
#endif
#define MONO_API_IMPORT
#define JAVA_INTEROP_API_IMPORT

#endif /* !defined(_MSC_VER) */

#if defined(MONO_DLL_EXPORT)
#define MONO_API MONO_API_EXPORT
#elif defined(MONO_DLL_IMPORT)
#define MONO_API MONO_API_IMPORT
#else /* !defined(MONO_DLL_IMPORT) && !defined(MONO_API_IMPORT) */
#define MONO_API
#if defined(MONO_DLL_EXPORT) || defined(JAVA_INTEROP_DLL_EXPORT)
#define JAVA_INTEROP_API JAVA_INTEROP_API_EXPORT
#elif defined(MONO_DLL_IMPORT) || defined(JAVA_INTEROP_DLL_IMPORT)
#define JAVA_INTEROP_API JAVA_INTEROP_API_IMPORT
#else /* !defined(MONO_DLL_IMPORT) && !defined(MONO_DLL_EXPORT) */
#define JAVA_INTEROP_API
#endif /* MONO_DLL_EXPORT... */

#ifdef __cplusplus
Expand All @@ -37,8 +37,8 @@

JAVA_INTEROP_BEGIN_DECLS

MONO_API char *java_interop_strdup (const char* value);
MONO_API void java_interop_free (void *p);
JAVA_INTEROP_API char *java_interop_strdup (const char* value);
JAVA_INTEROP_API void java_interop_free (void *p);

JAVA_INTEROP_END_DECLS

Expand Down
Loading

0 comments on commit 4bfe49d

Please sign in to comment.