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

Fix TableKey / ObjKey conversion on Android x86 #2477

Merged
merged 16 commits into from
Jun 30, 2021
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
* \[Unity\] Fixed an issue where failing to weave an assembly due to modeling errors, would only show an error in the logs once and then fail opening a Realm with `No RealmObjects. Has linker stripped them?`. Now, the weaving errors will show up on every code change/weave attempt and the runtime error will explicitly suggest manually re-running the weaver. (Issue [#2310](https://github.com/realm/realm-dotnet/issues/2310))
* \[Unity\] Fixed an issue that would cause the app to hang on exit when using Sync. (PR [#2467](https://github.com/realm/realm-dotnet/pull/2467))
* \[Unity\] Fixed an issue that would cause the Unity editor on macOS to hang after assembly reload if the app uses Sync. (Issue [#2482](https://github.com/realm/realm-dotnet/issues/2482))
* Fixed an issue where a crash could happen on Android x86 due to converting UInt32 into TableKey and Int64 into ObjKey incorrectly. (Issue [#2456](https://github.com/realm/realm-dotnet/issues/2456))

### Enhancements
* None

### Compatibility
* Realm Studio: 11.0.0-alpha.0 or later.
* Realm Studio: 11.0.0 or later.

### Internal
* Using Core 11.0.3.
* GetHashCode() on objects now uses the table key in addition to the object key. (Issue [#2473](https://github.com/realm/realm-dotnet/issues/2473))

## 10.2.0 (2021-06-15)

Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm/DatabaseTypes/RealmObjectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ internal void SetOwner(Realm realm, ObjectHandle objectHandle, Metadata metadata
_realm = realm;
_objectHandle = objectHandle;
_metadata = metadata;
_hashCode = new Lazy<int>(() => _objectHandle.GetObjKey().GetHashCode());
_hashCode = new Lazy<int>(() => _objectHandle.GetObjHash());

if (_propertyChanged != null)
{
Expand Down
10 changes: 6 additions & 4 deletions Realm/Realm/Handles/ObjectHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal class ObjectHandle : NotifiableObjectHandleBase
private static class NativeMethods
{
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable IDE0049 // Naming Styles
#pragma warning disable SA1121 // Use built-in type alias

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_get_is_valid", CallingConvention = CallingConvention.Cdecl)]
Expand Down Expand Up @@ -66,8 +67,8 @@ private static class NativeMethods
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool equals_object(ObjectHandle handle, ObjectHandle otherHandle, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_get_obj_key", CallingConvention = CallingConvention.Cdecl)]
public static extern ObjKey get_obj_key(ObjectHandle handle, out NativeException ex);
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_get_hashcode", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 get_hashcode(ObjectHandle handle, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "object_get_backlinks", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr get_backlinks(ObjectHandle objectHandle, IntPtr property_index, out NativeException nativeException);
Expand Down Expand Up @@ -95,6 +96,7 @@ private static class NativeMethods
public static extern void get_schema(ObjectHandle objectHandle, IntPtr callback, out NativeException ex);

#pragma warning restore SA1121 // Use built-in type alias
#pragma warning restore IDE0049 // Naming Styles
#pragma warning restore IDE1006 // Naming Styles
}

Expand Down Expand Up @@ -138,9 +140,9 @@ public override bool Equals(object obj)
return result;
}

public ObjKey GetObjKey()
public int GetObjHash()
{
var result = NativeMethods.get_obj_key(this, out var nativeException);
var result = NativeMethods.get_hashcode(this, out var nativeException);
nativeException.ThrowIfNecessary();

return result;
Expand Down
22 changes: 12 additions & 10 deletions Realm/Realm/Handles/SharedRealmHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ internal class SharedRealmHandle : RealmHandle
private static class NativeMethods
{
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable SA1121 // Use built-in type alias

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NotifyRealmCallback(IntPtr stateHandle);
Expand Down Expand Up @@ -118,7 +119,7 @@ public static extern IntPtr open_with_sync_async(Configuration configuration, Sy
public static extern bool refresh(SharedRealmHandle sharedRealm, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_get_table_key", CallingConvention = CallingConvention.Cdecl)]
public static extern TableKey get_table_key(SharedRealmHandle sharedRealm, [MarshalAs(UnmanagedType.LPWStr)] string tableName, IntPtr tableNameLength, out NativeException ex);
public static extern UInt32 get_table_key(SharedRealmHandle sharedRealm, [MarshalAs(UnmanagedType.LPWStr)] string tableName, IntPtr tableNameLength, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_is_same_instance", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
Expand All @@ -141,10 +142,10 @@ public static extern IntPtr open_with_sync_async(Configuration configuration, Sy
public static extern void write_copy(SharedRealmHandle sharedRealm, [MarshalAs(UnmanagedType.LPWStr)] string path, IntPtr path_len, byte[] encryptionKey, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_create_object", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr create_object(SharedRealmHandle sharedRealm, TableKey table_key, out NativeException ex);
public static extern IntPtr create_object(SharedRealmHandle sharedRealm, UInt32 table_key, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_create_object_unique", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr create_object_unique(SharedRealmHandle sharedRealm, TableKey table_key, PrimitiveValue value,
public static extern IntPtr create_object_unique(SharedRealmHandle sharedRealm, UInt32 table_key, PrimitiveValue value,
[MarshalAs(UnmanagedType.U1)] bool update,
[MarshalAs(UnmanagedType.U1)] out bool is_new, out NativeException ex);

Expand Down Expand Up @@ -175,11 +176,12 @@ public static extern void install_callbacks(
public static extern IntPtr freeze(SharedRealmHandle sharedRealm, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_get_object_for_primary_key", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr get_object_for_primary_key(SharedRealmHandle realmHandle, TableKey table_key, PrimitiveValue value, out NativeException ex);
public static extern IntPtr get_object_for_primary_key(SharedRealmHandle realmHandle, UInt32 table_key, PrimitiveValue value, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_create_results", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr create_results(SharedRealmHandle sharedRealm, TableKey table_key, out NativeException ex);
public static extern IntPtr create_results(SharedRealmHandle sharedRealm, UInt32 table_key, out NativeException ex);

#pragma warning restore SA1121 // Use built-in type alias
#pragma warning restore IDE1006 // Naming Styles
}

Expand Down Expand Up @@ -340,7 +342,7 @@ public TableKey GetTableKey(string tableName)
{
var tableKey = NativeMethods.get_table_key(this, tableName, (IntPtr)tableName.Length, out var nativeException);
nativeException.ThrowIfNecessary();
return tableKey;
return new TableKey(tableKey);
}

public bool IsSameInstance(SharedRealmHandle other)
Expand Down Expand Up @@ -405,7 +407,7 @@ public RealmSchema GetSchema()

public ObjectHandle CreateObject(TableKey tableKey)
{
var result = NativeMethods.create_object(this, tableKey, out NativeException ex);
var result = NativeMethods.create_object(this, tableKey.Value, out NativeException ex);
ex.ThrowIfNecessary();
return new ObjectHandle(this, result);
}
Expand All @@ -427,7 +429,7 @@ public ObjectHandle CreateObjectWithPrimaryKey(Property pkProperty, object prima
};

var (primitiveValue, handles) = pkValue.ToNative();
var result = NativeMethods.create_object_unique(this, tableKey, primitiveValue, update, out isNew, out var ex);
var result = NativeMethods.create_object_unique(this, tableKey.Value, primitiveValue, update, out isNew, out var ex);
handles?.Dispose();
ex.ThrowIfNecessary();
return new ObjectHandle(this, result);
Expand All @@ -448,7 +450,7 @@ public SharedRealmHandle Freeze()
public bool TryFindObject(TableKey tableKey, in RealmValue id, out ObjectHandle objectHandle)
{
var (primitiveValue, handles) = id.ToNative();
var result = NativeMethods.get_object_for_primary_key(this, tableKey, primitiveValue, out var ex);
var result = NativeMethods.get_object_for_primary_key(this, tableKey.Value, primitiveValue, out var ex);
handles?.Dispose();
ex.ThrowIfNecessary();

Expand All @@ -464,7 +466,7 @@ public bool TryFindObject(TableKey tableKey, in RealmValue id, out ObjectHandle

public ResultsHandle CreateResults(TableKey tableKey)
{
var result = NativeMethods.create_results(this, tableKey, out var nativeException);
var result = NativeMethods.create_results(this, tableKey.Value, out var nativeException);
nativeException.ThrowIfNecessary();
return new ResultsHandle(this, result);
}
Expand Down
8 changes: 6 additions & 2 deletions Realm/Realm/Handles/SortDescriptorHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@ internal class SortDescriptorHandle : RealmHandle
{
private static class NativeMethods
{
#pragma warning disable SA1121 // Use built-in type alias

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "sort_descriptor_destroy", CallingConvention = CallingConvention.Cdecl)]
public static extern void destroy(IntPtr queryHandle);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "sort_descriptor_add_clause", CallingConvention = CallingConvention.Cdecl)]
public static extern void add_clause(SortDescriptorHandle descriptor, TableKey table_key, SharedRealmHandle realm,
public static extern void add_clause(SortDescriptorHandle descriptor, UInt32 table_key, SharedRealmHandle realm,
[MarshalAs(UnmanagedType.LPArray), In] IntPtr[] property_index_chain, IntPtr column_keys_count,
[MarshalAs(UnmanagedType.U1)] bool ascending, [MarshalAs(UnmanagedType.U1)] bool replacing,
out NativeException ex);

#pragma warning restore SA1121 // Use built-in type alias
}

public SortDescriptorHandle(RealmHandle root, IntPtr handle) : base(root, handle)
Expand All @@ -42,7 +46,7 @@ public SortDescriptorHandle(RealmHandle root, IntPtr handle) : base(root, handle

public void AddClause(SharedRealmHandle realm, TableKey tableKey, IntPtr[] propertyIndexChain, bool ascending, bool replacing)
{
NativeMethods.add_clause(this, tableKey, realm, propertyIndexChain, (IntPtr)propertyIndexChain.Length, ascending, replacing, out var nativeException);
NativeMethods.add_clause(this, tableKey.Value, realm, propertyIndexChain, (IntPtr)propertyIndexChain.Length, ascending, replacing, out var nativeException);
nativeException.ThrowIfNecessary();
}

Expand Down
39 changes: 0 additions & 39 deletions Realm/Realm/Native/ObjKey.cs

This file was deleted.

17 changes: 10 additions & 7 deletions Realm/Realm/Native/TableKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,26 @@
////////////////////////////////////////////////////////////////////////////

using System;
using System.Runtime.InteropServices;

namespace Realms.Native
{
[StructLayout(LayoutKind.Sequential)]
internal struct TableKey : IEquatable<TableKey>
{
private UInt32 value;
public readonly UInt32 Value;

public bool Equals(TableKey other) => value.Equals(other.value);
public TableKey(UInt32 value)
{
Value = value;
}

public bool Equals(TableKey other) => Value.Equals(other.Value);

public override bool Equals(object obj) => obj is TableKey other && Equals(other);

public override int GetHashCode() => value.GetHashCode();
public override int GetHashCode() => Value.GetHashCode();

public static bool operator ==(TableKey left, TableKey right) => left.value == right.value;
public static bool operator ==(TableKey left, TableKey right) => left.Value == right.Value;

public static bool operator !=(TableKey left, TableKey right) => left.value != right.value;
public static bool operator !=(TableKey left, TableKey right) => left.Value != right.Value;
}
}
11 changes: 8 additions & 3 deletions wrappers/src/object_cs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,16 @@ extern "C" {
});
}

REALM_EXPORT int64_t object_get_obj_key(const Object& object, NativeException::Marshallable& ex)
REALM_EXPORT int32_t object_get_hashcode(const Object& object, NativeException::Marshallable& ex)
{
return handle_errors(ex, [&]() {
// ObjKey is incompatible with C, so we return just the value.
return object.obj().get_key().value;
int32_t table_key_value = static_cast<int32_t>(object.obj().get_table()->get_key().value);
int32_t object_key_value = static_cast<int32_t>(object.obj().get_key().value);

int32_t hashCode = -986587137;
hashCode = (hashCode * -1521134295) + table_key_value;
hashCode = (hashCode * -1521134295) + object_key_value;
return hashCode;
});
}

Expand Down