David Klempfner
David Klempfner

Reputation: 9870

sscanf returns 0 when run in CIL

I have this IL code from Expert .NET 2.0 IL Assembler by Serge Lidin:

This is in a file called CilTest.il:

//----------- Program header
.assembly extern  mscorlib { auto }
.assembly OddOrEven  { }
.module OddOrEven.exe
//----------- Class declaration
.namespace Odd.or {
    .class public auto ansi Even extends [mscorlib]System.Object {
//----------- Field declaration
        .field public static int32 val
//----------- Method declaration
        .method public static void check( ) cil managed {
            .entrypoint
            .locals init (int32 Retval)
        AskForNumber:
            ldstr "Enter a number"
            call void [mscorlib]System.Console::WriteLine (string)
            call string [mscorlib]System.Console::ReadLine ()
            ldsflda valuetype CharArray8 Format
            ldsflda int32 Odd.or.Even::val
            call vararg int32 sscanf(string,int8*,...,int32*)
            stloc Retval
            ldloc Retval
            brfalse Error
            ldsfld int32 Odd.or.Even::val
            ldc.i4 1
            and
            brfalse ItsEven
            ldstr "odd!"
            br PrintAndReturn
        ItsEven:
            ldstr "even!"
            br PrintAndReturn
        Error:
            ldstr "How rude!"
        PrintAndReturn:
            call void [mscorlib]System.Console::WriteLine (string)
            ldloc Retval
            brtrue AskForNumber
            ret
        } // End of method
    } // End of class
} // End of namespace
//----------- Global items
.field public static valuetype CharArray8 Format at FormatData
//----------- Data declaration
.data FormatData = bytearray(25 64 00 00 00 00 00 00) // % d . . . . . .
//----------- Value type as placeholder
.class public explicit CharArray8 
              extends [mscorlib]System.ValueType { .size 8  }
//----------- Calling unmanaged code
.method public static pinvokeimpl("msvcrt.dll" cdecl) 
    vararg int32 sscanf(string,int8*) cil managed { }

The following file is in the same folder and called CilTest.ilproj:

<Project Sdk="Microsoft.Net.Sdk.il/7.0.0">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
  </PropertyGroup>
</Project>

I'm compiling the code using:

dotnet build -r win-x64 --self-contained -c release

When I run the code, I get this error:

enter image description here

It seems as though the call to sscanf returns 0 successful formatted strings:

call vararg int32 sscanf(string,int8*,...,int32*)

Why is sscanf() not working?

Is there a way to debug the code so I can see why sscanf() is not working?

Upvotes: 1

Views: 88

Answers (2)

Serge Lidin
Serge Lidin

Reputation: 36

Add keyword preservesig after cil managed, like this:

//----------- Calling unmanaged code
.method public static pinvokeimpl("msvcrt.dll" cdecl) 
    vararg int32 sscanf(string,int8*) cil managed preservesig { }

In .NET implementations later than 2.0 this keyword is required to indicate that the return value of the P/Invoke method has to be preserved.

Upvotes: 2

Bitwise_Gamgee
Bitwise_Gamgee

Reputation: 44

I have limited experience but have always used the PInvoke method when calling sscanf in this manner. We used something along the lines of :

.method private pinvokeimpl("msvcrt.dll" cdec1)
    int32 sscanf _pinvoke(string, int8*)
cil; managed { }

You can also just write your own version of sscanf(MSVC)(GLIBC), as it's a relatively simple function and incorporate that into your program.

Upvotes: 1

Related Questions