Runtime: Open device using operating system open-function returns EISDIR using .NET Core

Created on 25 Sep 2018  路  13Comments  路  Source: dotnet/runtime

_From @FrankPfattheicher on August 24, 2018 14:15_

Open device using operating system open-function returns EISDIR using .NET Core

I am using interop to access basic file api of linux (Respberry Pi).

[DllImport("libc", SetLastError = true, CharSet = CharSet.Auto)] internal static extern int open(string fileName, int mode);

Opening a device like tty

var handle = Interop.open("/dev/tty", Interop.O_RDWR);

fails with errno=21 (EISDIR)

Same code running full framework (Mono 4.6.2) the device is opened successfully and i can use read and write!

Where comes this difference?

_Copied from original issue: dotnet/core#1891_

area-System.Runtime.InteropServices documentation

All 13 comments

can you run this with strace -r -f -s 100 -e trace=file dotnet foo.dll.
That should provide some info what is going on.

I have retried the problem after update to core 2.1.302, now i get ERRNO=0.
Opening the device using File.Open works and i can get the correct handle using

handle = file.SafeFileHandle.DangerousGetHandle().ToInt32();
Cant find any more information in strace :-(

Full test code:
`
using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Interop
{
class Program
{
const string device = "/dev/tty";
const int O_RDONLY = 0x00000000;
const int O_WRONLY = 0x00000001;
const int O_RDWR = 0x00000002;
const int O_NONBLOCK = 0x00004000;

    [DllImport("libc", SetLastError = true, CharSet = CharSet.Auto)] 
    internal static extern int open(string fileName, int mode);

    [DllImport("libc", SetLastError = true, CharSet = CharSet.Auto)] 
    internal static extern int close(int file);

    static void Main(string[] args)
    {
        var handle = open(device, O_RDONLY | O_NONBLOCK);
        Console.WriteLine($"open {device} = {handle}");

        if(handle > 0)
        {
            Console.WriteLine("OK !");
            close(handle);
        }
        else
        {
            var err = Marshal.GetLastWin32Error();
            Console.WriteLine($"ERROR = {err}");

            var file = File.Open(device, FileMode.Open, FileAccess.ReadWrite);
            handle = file.SafeFileHandle.DangerousGetHandle().ToInt32();
            Console.WriteLine($"File.Open {device} = {handle}");

            close(handle);
        }
    }
}

}
`

And the strace file

strace.txt

[pid 7522] 0.007177 openat(AT_FDCWD, "/dev/tty", O_RDWR|O_CLOEXEC) = 24

this is from File.Open(). I don't see any attempt from the pinvoke.
I did try this on my Ubuntu and it did not work until I took out the CharSet = CharSet.Auto
With that strace shows attempt and it fails as the flags are different on x86.

I did try the code as you posted on my Raspberry and it worked as exected:

pi@raspberrypi:~/aa $  ~/dotnet-2.1.302/dotnet run
open /dev/tty = 22
OK !

so this looks like some kind of environmental problem. Do you have LANG or LC_??? set?

I work with .NET core on a ARM device and also stumbled across this issue by trying to open /dev/rtc with .NET Core Version: 2.1.5 Commit: 290303f510

Using File.Open did the job the same as removing the DllImport attribute CharSet = CharSet.Auto

Yes, removing the DllImport attribute CharSet = CharSet.Auto resolved the problem.

I wonder what's going wrong using the attribute in Core while there is no porblem in Full Framework...

any idea @janvorli ? This seems more like runtime issue.

I've found this piece of code in the DllImport functionality in src/vm/dllimport.cpp:

    else if (charSetMask == pmCharSetUnicode || charSetMask == pmCharSetAuto)
    {
        // Since Win9x isn't supported anymore, pmCharSetAuto always represents unicode strings.
        SetCharSet (nltUnicode);
    }

I guess that explains the problem. But it seems to me that it should be different for Unix where the native string encoding is 8 bit (I believe "unicode" here means UTF-16 or UCS-2). @jkotas, @jeffschwMSFT any thoughts here?

.NET's definition of unicode, which matches Windows but not Unix, has been a peranial issue. If we have a targeted fix to help unblock people that may make sense, as the larger potential change is only on the horizon.

cc @AaronRobinsonMSFT

This is related to https://github.com/dotnet/coreclr/issues/20504 . .NET Core has different defaults than Mono for string marshaling on Unix.

could this be fixed as documentation? It seems like using explicit CharSet or no charset would be reasonable. Perhaps we can close this issue and use linked coreclr for tracking.

@jkoritzinsky If you are still working on the docs for P/Invoke, can you check the current details for this? I know you hit some of these issues when adding tests. Seems like people have received enough pain - we should be very clear about about this discrepancy.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iCodeWebApps picture iCodeWebApps  路  3Comments

Timovzl picture Timovzl  路  3Comments

jamesqo picture jamesqo  路  3Comments

v0l picture v0l  路  3Comments

bencz picture bencz  路  3Comments