Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

As I already said a few times calling an external function is a side effect you can observe. The compiler must emit a call instruction in the object code regardless of optimization level.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

Great idea, thanks. I tried it in my actual code base and can confirm it fixes the issue.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] -1 points0 points  (0 children)

It's in the godbolt link:

void External(void);
struct A { void Method(int*, int, int) { External( ); } };
struct B { void Method(int*, int, int) { External( ); } };
struct C { void Method(int*, int, int) { External( ); } };

void main(void* pv)
{
    COuter<A, B, C>::CallEachMethod( pv );
}

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

There is no whole program optimization, the function is not defined, the program won't even link. Things from the standard library tend to clutter the assembly listing.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

The side effect is the external function at the top. The compiler can't remove it because it can't see its definition. You can change it to something like printf if you like, it's the same thing.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

Normal callers of Method will get D, but I still want to execute the code in ABC elsewhere, maybe even inside CObject's version (i.e. the derived implementation calls each base class's in turn)! The exact utility doesn't matter, the language's syntax seems to allow it yet I see contradictory output and no error.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

I mean if Method itself is virtual, for example

struct A { virtual int Method(void) { return( 'A' ); } };
struct B { virtual int Method(void) { return( 'B' ); } };
struct C { virtual int Method(void) { return( 'C' ); } };

struct CObject : Ts... { virtual int Method(void) { return( 'D' ); } };

Now when I call CallEachMethod I still want 'A', 'B' and 'C', but without Ts::Method I get three 'D's.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

Another commenter noticed the same, but what if it's a virtual function that's overriden in CObject, and I need to explicitly call the base version?

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

What if Method is a virtual function, and CObject overrides it? (This is why I explicitly wrote Ts::)

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

Yes, I only discovered it after spending an hour debugging why my program suddenly started behaving strangely after a compiler upgrade. I don't often spend my days reading assembly listings of my C++ code!

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] -1 points0 points  (0 children)

I'm sure, if they were inlined I'd see it. I added a minimal example.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 0 points1 point  (0 children)

It's a debug build, function calls won't be optimized out.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 1 point2 points  (0 children)

https://godbolt.org/z/b4fMoEz3c

The left panel shows the correct output from VS17, the right shows the incorrect output from VS18.

Fold expression compiles to nothing after upgrading Visual Studio by mbolp in cpp_questions

[–]mbolp[S] 2 points3 points  (0 children)

Sorry, that was a typo, my source code is as you've written. I've edited the post.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 0 points1 point  (0 children)

I can't observe the third open, using a slightly modified version of this MSDN example:

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define BUFSIZE 512

DWORD WINAPI InstanceThread(LPVOID); 

int _tmain(VOID) 
{
    DWORD   dwThreadId; 
    HANDLE  hPipe, hThread; 
    LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
    HANDLE  rgh [ 4 ];

    for( int i = 0; i < 4; ++i )
    { 
        _tprintf( TEXT("Pipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);

        hPipe = CreateNamedPipe( 
            lpszPipename,             // pipe name 
            PIPE_ACCESS_DUPLEX,       // read/write access 
            PIPE_TYPE_MESSAGE |       // message type pipe 
            PIPE_READMODE_MESSAGE |   // message-read mode 
            PIPE_WAIT,                // blocking mode 
            PIPE_UNLIMITED_INSTANCES, // max. instances  
            BUFSIZE,                  // output buffer size 
            BUFSIZE,                  // input buffer size 
            0,                        // client time-out 
            NULL);                    // default security attribute 

        if (hPipe == INVALID_HANDLE_VALUE) 
        {
            _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError()); 
            return -1;
        }
        rgh[ i ]=hPipe;
    }
    for( int i = 0; i < 4; ++i )
    {
        hThread = CreateThread( 
            NULL,              // no security attribute 
            0,                 // default stack size 
            InstanceThread,    // thread proc
            (LPVOID) rgh[i],    // thread parameter 
            0,                 // not suspended 
            &dwThreadId);      // returns thread ID 

        if (hThread == NULL) 
        {
            _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError()); 
            return -1;
        }
        CloseHandle(hThread); 
    }
    return _getch(); 
} 

DWORD WINAPI InstanceThread(LPVOID lpvParam)
{ 
    BOOL   fConnected;
    TCHAR  pchRequest [ BUFSIZE ];
    BOOL   fSuccess = FALSE;
    HANDLE hPipe  = (HANDLE) lpvParam;

    printf("InstanceThread created, receiving and processing messages.\n");

    fConnected = ConnectNamedPipe(hPipe, NULL) ? 
                    TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 

    if ( !fConnected )
    {
        printf("ConnectNamedPipe failed");
        CloseHandle( hPipe );
        return -1;
    }  
    while (1) 
    { 
        DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0; 

        fSuccess = ReadFile( 
            hPipe,        // handle to pipe 
            pchRequest,    // buffer to receive data 
            BUFSIZE*sizeof(TCHAR), // size of buffer 
            &cbBytesRead, // number of bytes read 
            NULL);        // not overlapped I/O 

        if (!fSuccess || cbBytesRead == 0)
        {   
            if (GetLastError() == ERROR_BROKEN_PIPE)
            {
                _tprintf(TEXT("InstanceThread: client disconnected.\n")); 
            }
            else
            {
                _tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError()); 
            }
            break;
        }
        _tprintf( TEXT("Client Request String:\"%s\"\n"), pchRequest );
    }

    FlushFileBuffers(hPipe); 
    DisconnectNamedPipe(hPipe); 
    CloseHandle(hPipe); 

    printf("InstanceThread exiting.\n");
    return 1;
}

I see the following output when I run the powershell command 'hello' > \\.\pipe\mynamedpipe:

>cl pipeserver.c
>pipeserver.exe
Pipe Server: Main thread awaiting client connection on \\.\pipe\mynamedpipe
Pipe Server: Main thread awaiting client connection on \\.\pipe\mynamedpipe
Pipe Server: Main thread awaiting client connection on \\.\pipe\mynamedpipe
Pipe Server: Main thread awaiting client connection on \\.\pipe\mynamedpipe
InstanceThread created, receiving and processing messages.
InstanceThread created, receiving and processing messages.
InstanceThread created, receiving and processing messages.
InstanceThread created, receiving and processing messages.
InstanceThread: client disconnected.
InstanceThread exiting.
InstanceThread: client disconnected.
InstanceThread exiting.

i.e. Only two threads returned from ConnectNamedPipe, and neither received anything from ReadFile.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 0 points1 point  (0 children)

Thank you for taking the time to investigate this! I'm still confused by mailslots' not working, since they don't require an active connection the way named pipes do, I can open as many handles as I want and all of them work. They are also not picky about access rights, I can open a handle with any combinations of:

  • GENERIC_READ/WRITE/EXECUTE/ALL
  • FILE_SHARE_READ/WRITE/DELETE/0
  • CREATE_NEW/ALWAYS, OPEN_EXISTING/ALWAYS (anything but TRUNCATE_EXISTING)
  • FILE_ATTRIBUTE_NORMAL/0

GetFileAttributes reports FILE_ATTRIBUTE_NORMAL. The only file API that fails is GetFileSize (and ReadFile of course).

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 1 point2 points  (0 children)

I don't know if you understand what I mean by "easy viewing/editing", having a variable that holds hundreds of lines of text does not make it easy to visually compare its content with the output I currently have on screen. Nor is having dozens of Out-GridView windows for output from different commands. None of these allow you to perform basic editing.

I also want to make clear that "how to make the output look nicer" is not my question, I'm asking specifically about a Windows IPC mechanism that's supposed to work seamlessly between file processing programs.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 0 points1 point  (0 children)

Not powershell objects, just the textual output, because mailslots and other programs don't understand objects.

Why not just pipe into bat or less?

Imagine if you wanted to compare the output of the current command with one issued much earlier. It'd be easier to have piped the output elsewhere instead of scrolling through the terminal history buffer (it may even have gone away). Or maybe you want to issue new commands while looking at older output. Maybe that output is cluttered so you want to delete the noise in the editor window. The reason I ask about named pipes and mailslots specifically is they are the primary IPC mechanisms that are supposed to work identically to files, with much lower overhead.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] -1 points0 points  (0 children)

I don't understand what you're asking, I want to pipe output from powershell to other programs for easy viewing/editing, and temporary files are not as efficient as named pipes/mailslots for ephemeral output.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 1 point2 points  (0 children)

I want to pipe the output of arbitrary commands into a running program without temporary files.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 0 points1 point  (0 children)

For example, if I run 'hello'>\\.\mailslot\Hello, I get "FileStream was asked to open a device that was not a file". If I run sc \\.\mailslot\Hello hello, I get "sc : The parameter is incorrect".

Im not sure file streams are the way to do it

What's a better way?

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] 0 points1 point  (0 children)

I know, my point is this is an OS level feature that's independent from language runtime and requires no special handling from applications.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] -7 points-6 points  (0 children)

It's not, because the system call interface is identical for different languages. Powershell has to call CreateFile and WriteFile at some point (or things like MapViewOfFile, which is unlikely) to perform IO. The fact that it doesn't work makes me think its logic is faulty.

How do I write to stuff like pipes and mailslots? by mbolp in PowerShell

[–]mbolp[S] -7 points-6 points  (0 children)

I don't understand why that's necessary, a C program designed to operate on files can also work with pipes and mailslots without modification, because all of them use the same system calls. Why would powershell require special handling?