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

Arithmetic operation resulted in an overflow #121

Open
ststeiger opened this issue Sep 5, 2018 · 7 comments
Open

Arithmetic operation resulted in an overflow #121

ststeiger opened this issue Sep 5, 2018 · 7 comments

Comments

@ststeiger
Copy link

ststeiger commented Sep 5, 2018

On .NET-Core 2.0 x64, I get "Arithmetic operation resulted in an overflow." on reading the ascender...

/// <summary>
/// Gets the ascender in 26.6 fractional pixels.
/// </summary>
/// <see cref="Face"/>
public Fixed26Dot6 Ascender
{
    get
    {
        // Here => (int)
        return Fixed26Dot6.FromRawValue((int)rec.ascender);
    }
}

I don't get what you're doing there - casting an int64 to an int32 ?
This can't work...

SharpFont.Native.Init();

SharpFont.Library lib = new SharpFont.Library();
SharpFont.Face fontFace = new SharpFont.Face(lib, @"C:\Windows\Fonts\tahoma.ttf");
            
float size = 12;
if (fontFace!= null)
    // fontFace.SetCharSize(0, size, 0, 96);
    fontFace.SetCharSize(size, size, 96, 96);

System.Console.WriteLine(fontFace.Size.Metrics.Ascender.ToDouble()); // kaboom...
System.Console.WriteLine(fontFace.Size.Metrics.Descender.ToSingle());
System.Console.WriteLine(fontFace.Size.Metrics.Height.ToSingle());

Dll's from SharpFont\Dependencies\freetype2\2.6-alldeps\msvc12\x64


namespace SharpFont
{


    public class Native
    {

        public static void Init()
        {
            if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
                return;

            System.Reflection.Assembly ass = typeof(Native).Assembly;
            string dir = System.IO.Path.GetDirectoryName(ass.Location);
            int bitness = System.IntPtr.Size * 8;
            string[] embeddedResources = ass.GetManifestResourceNames();
            string freetypeLib = "freetype6.x86-" + bitness.ToString() + ".dll";
            string fileName = System.IO.Path.Combine(dir, "freetype6.dll");

            string found = null;
            for (int i = 0; i < embeddedResources.Length; ++i)
            {
                if (embeddedResources[i].EndsWith(freetypeLib, System.StringComparison.OrdinalIgnoreCase))
                {
                    found = embeddedResources[i];
                    break;
                }
            } // Next i 

            if (string.IsNullOrEmpty(found))
                throw new System.Exception("Resource \"" + freetypeLib + "\"not found");

            using (System.IO.Stream strm = ass.GetManifestResourceStream(found))
            {
                using (System.IO.Stream output = System.IO.File.Create(fileName))
                {
                    strm.CopyTo(output);
                } // End Using output 

            } // End Using strm 

        } // End Sub Init 


    } // End Class Native 


} // End Namespace SharpFont 

Note:
On Linux with the same code, this runs just fine (font file path changed of course).

@ststeiger
Copy link
Author

ststeiger commented Sep 6, 2018

The types for 64 bit Windows are incorrect.

You have

    using FT_Long = System.IntPtr;
    using FT_ULong = System.UIntPtr;

But this should be

#if WINDOWS
    using FT_Long = System.Int32;
    using FT_ULong = System.UInt32;    
#else
    using FT_Long = System.IntPtr;
    using FT_ULong = System.UIntPtr;
#endif
// https://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html
// (freetype/fttypes.h).
// FT_ULong:  typedef unsigned long  FT_ULong;
// FT_Long:   typedef signed long FT_Long;

// Size of 'long integer' data type (C++) 
// on various architectures and OS
// Windows   IA-32                4 bytes
// Windows   Intel® 64 or IA-64   4 bytes
// Linux     IA-32                4 bytes
// Linux     Intel® 64 or IA-64   8 bytes
// Mac OS X  IA-32                4 bytes
// Mac OS X  Intel® 64 or IA-64   8 bytes
size of ulong in bytes x86-32 x86-64
Linux 4 8
Windows 4 4
MacOS 4 8

@HinTak
Copy link
Contributor

HinTak commented Sep 6, 2018

It is complicated. Whereas what you are saying is strictly speak correct in the FreeType universe:

#if WINDOWS
    using FT_Long = System.Int32;
    using FT_ULong = System.UInt32;    
#else
    using FT_Long = System.IntPtr;
    using FT_ULong = System.UIntPtr;
#endif

SharpFont suffers from some limitation from inconsistensies between C# and c-runtime on windows.
To work around that, a special build of freetype is needed, patched with
freetype2/win64.patch from http://github.com/Robmaister/SharpFont.Dependencies. Are you doing that, or are you using vanilla-built FreeType?

@ststeiger
Copy link
Author

Yea, I noticed.
It's impossible to create ONE cross-platform binary that way.

I used the exact BINARY version from SharpFont.Dependencies.
Unless those aren't patched, it has these patches.

If those are patched, and you know they are working on x64 on Windows, then it is possible that some other program installed a version of freetype in PATH without me knowing about that, and that it's using that - dllmap doesn't work in .NET Core btw - yet another problem.

@HinTak
Copy link
Contributor

HinTak commented Sep 7, 2018

Hmm, you probably should do new Fixed26Dot6() like the SetCharSize() calls in https://github.com/HinTak/Font-Validator/blob/master/Compat/Compat.cs . I am not sure C# is clever enough to convert - probably not . The problem is that float is 32-bit wide but not actually in Fixed26Dot6 which is also 32-bit wide. So you could be calling SetCharSize with some insane values, which can result in overflow in Fixed26Dot6 operations. Nothing to do with SharpFont but FreeType telling you that you are sending insane values as inputs.

@ststeiger
Copy link
Author

ststeiger commented Sep 7, 2018

It has nothing to do with float - it fails on (int)rec.ascender casting an int64 to int32.
Which might indicate the native dll hasn't fully been patched - some places left as is, and it reads the wrong data.

By using regex to replace your FT_Long with mine, and using an unpatched freetype version, it works.
Though now I have to build with a define depending on target platform.

Just checked - there is no freetype.dll in PATH anywhere.

@HinTak
Copy link
Contributor

HinTak commented Sep 8, 2018

I don't have access to 64-bit windows machine at the moment, but with win64 mono under 64-bit wine, I get same answer under win64 as under x86_64 linux, which is

17
-4
19

Granted I am using the freetype dll's I built though. You can have a go, grabbing the whole directory of https://github.com/HinTak/Font-Validator/tree/master/bin/Win64 . (it is built with mingw so have different dependencies; also I use a slightly larger win64 patch than freetype2/win64.patch from http://github.com/Robmaister/SharpFont.Dependencies ).

FWIW, I am trying to look at HinTak/Font-Validator#27 , for my own purposes.

@db300
Copy link

db300 commented May 2, 2020

I have same problem.
when the following code is executed, the same exception Arithmetic operation resulted in an overflow is thrown.
float gAdvanceX = (float) face.Glyph.Advance.X; // same as the advance in metrics

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants