• Re: srand(0)

    From Keith Thompson@3:633/10 to All on Tuesday, December 30, 2025 19:37:25
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:
    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members argv[0]
    through argv[argc?1] inclusive shall contain pointers to strings
    which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    That's not clear. Linux (since 2022) guarantees argc>=1. I don't
    know whether Windows makes a similar guarantee, but it's entirely
    plausible that it could.

    But not all systems guarantee argc>=1, so any portable code shouldn't
    make assumptions beyond what's guaranteed by ISO C.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Wednesday, December 31, 2025 04:51:11
    On Tue, 30 Dec 2025 19:35:12 -0800, Keith Thompson wrote:

    Summary: Some systems guarantee that argc>=1 and argv[0] points to
    a valid string, but software that's intended to be portable should
    tolerate argc==0 and argv[0]==NULL.

    For more information, see
    <https://github.com/Keith-S-Thompson/argv0>.

    Thanks Keith so I'll roll with ISO:

    int main(int argc, char *argv[]) {

    // ISO: if app named 'moo' play bulls & cows else mastermind
    const char *p = (argc > 0 && argv && argv[0]) ? argv[0] : "";
    const char *m = strrchr(p, '/');
    MOO = strcmp(m ? m + 1 : p, "moo") == 0;

    int s = get_seed(argc, argv); // returns default seed if not supplied

    fflush(stdout);
    fprintf(stderr, "%d\n", play(s)); // print seed to stderr

    return 0;
    }

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, December 31, 2025 09:37:08
    On Wed, 31 Dec 2025 03:28:03 -0000 (UTC), Michael Sanders wrote:

    On Wed, 31 Dec 2025 03:10:52 -0000 (UTC), Lawrence D?Oliveiro wrote:

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    Some windows snippets:

    Are there any standards for how C argc/argv are supposed to behave on
    Windows?

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Wednesday, December 31, 2025 15:15:02
    On Tue, 30 Dec 2025 19:35:12 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael Sanders <porkchop@invalid.foo> writes:
    On Tue, 30 Dec 2025 18:42:30 GMT, Scott Lurndal wrote:
    What if 'argv[0]' is NULL (and argc == 0)?

    Well, seems we have to make a choice, ISO vs. POSIX:

    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    [...]

    *POSIX.1-2017 (and later)*

    POSIX execve() specification:

    The argument argv is an array of character pointers
    to null-terminated strings.

    The application shall ensure that argv[0] points to a filename
    string that is associated with the process being started.

    [...]

    What say you?

    It happens that I recently spent some time looking into this.

    As you say, POSIX requires argc >= 1, but ISO C only guarantees
    argc >= 0.

    If argc == 0, a program that assumes argv[0] is non-null
    can run into serious problems if that assumption is invalid.
    In particular, a program called "pkexec" would try to traverse
    arguments starting with argv[1], which logically doesn't
    exist if argc==0. Due to the way program arguments are laid
    out in memory, argv[1] is also envp[0]. Frivolity ensued.
    See <https://nvd.nist.gov/vuln/detail/cve-2021-4034>.

    The Linux kernel updated execve to ensure that the invoked program
    has argc>=1. It was patched in early 2022. NetBSD still has this vulnerability.

    Summary: Some systems guarantee that argc>=1 and argv[0] points to
    a valid string, but software that's intended to be portable should
    tolerate argc==0 and argv[0]==NULL.

    For more information, see
    <https://github.com/Keith-S-Thompson/argv0>.


    If you are interested in behavior on non-POSIX systems, primarily
    Windows, but possibly others as well (e.g. VMS) then using exec() in
    caller sounds like a bad idea. It just not how these systems work and
    not how people write programs on them.
    Even when exec() *appears* to works in some environments (like
    msys2) it likely emulated by spawn() followed by exit().

    I'd implement caller with spawn(). I suppose that even on POSIX it is
    more idiomatic.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Wednesday, December 31, 2025 15:29:09
    On Wed, 31 Dec 2025 03:10:52 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:

    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members argv[0] through argv[argc?1] inclusive shall contain pointers to strings
    which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    How did you come to this conclusion?
    Keith's test appears to show the opposite - he was not able to convince
    the Windows system to call application with empty argv list.
    Of course, he tried only one way out of many, but knowing how native
    Windows system call works, it appears extremely likely that on Windows
    argc < 1 is impossible.

    https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-pr ocessthreadsapi-createprocessa


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Wednesday, December 31, 2025 17:24:29
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:
    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members argv[0]
    through argv[argc?1] inclusive shall contain pointers to strings
    which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    That's not clear. Linux (since 2022) guarantees argc>=1.

    Does it? That seems to be up to the shell, since the exec()
    manual pages on the latest Fedora Core release don't indicate
    that argv[0] must be initialized or that argc be greater than zero.



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Paul@3:633/10 to All on Wednesday, December 31, 2025 12:30:02
    On Tue, 12/30/2025 10:37 PM, Keith Thompson wrote:
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:
    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members argv[0]
    through argv[argc?1] inclusive shall contain pointers to strings
    which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    That's not clear. Linux (since 2022) guarantees argc>=1. I don't
    know whether Windows makes a similar guarantee, but it's entirely
    plausible that it could.

    But not all systems guarantee argc>=1, so any portable code shouldn't
    make assumptions beyond what's guaranteed by ISO C.


    The Windows guarantee is with MSVC, according to this answer.

    ********** CoPilot Question **********

    Does the Windows operating system guarantee that argc >= 1 for an EXE program ?

    argv[0] usually contains the program absolute path.

    ********** CoPilot Answer ************

    Here?s the clear, standards?grounded, Windows?specific answer you?re looking for ? with citations from the search results.

    # **Short Answer**
    **Yes. On Windows, when using the Microsoft C runtime (MSVCRT), argc
    is always guaranteed to be ò 1**, and ** argv[0] always exists**.
    However, **Windows itself does *not* guarantee what argv[0] contains** -
    only that the C runtime *treats* it as the program name.

    ---

    # **What Windows Guarantees vs. What the C Runtime Guarantees**

    ### **Microsoft C Runtime Guarantee**
    Microsoft?s documentation explicitly states:

    - *?Since the program name is considered an argument, the value of argc is at least one.?*

    So if your EXE is built with MSVC and uses the standard main or wmain , you can rely on:

    - argc >= 1
    - argv[0] is a valid null?terminated string
    - argv[argc] == NULL

    ### **MSVC Startup Code Behavior**
    MSVC startup code parses the command line and
    **always inserts the program name as argv[0] ** (quoted if needed).

    ---

    # **What Windows *Does Not* Guarantee**
    Windows itself does **not** enforce that the first token of the command line
    is the executable name. This is a convention, not a rule:

    - * By convention the module name ... is the first argument ... Note that this is
    only a convention and is not enforced in any way. *

    This means:

    - A caller can technically pass *anything* as the first token.
    - A process created via
  • From bart@3:633/10 to All on Wednesday, December 31, 2025 18:42:45
    On 31/12/2025 17:30, Paul wrote:
    On Tue, 12/30/2025 10:37 PM, Keith Thompson wrote:
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:
    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members argv[0]
    through argv[argc?1] inclusive shall contain pointers to strings
    which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    That's not clear. Linux (since 2022) guarantees argc>=1. I don't
    know whether Windows makes a similar guarantee, but it's entirely
    plausible that it could.

    But not all systems guarantee argc>=1, so any portable code shouldn't
    make assumptions beyond what's guaranteed by ISO C.


    The Windows guarantee is with MSVC, according to this answer.

    ********** CoPilot Question **********

    Does the Windows operating system guarantee that argc >= 1 for an EXE program ?

    argv[0] usually contains the program absolute path.

    ********** CoPilot Answer ************

    Here?s the clear, standards?grounded, Windows?specific answer you?re looking for ? with citations from the search results.

    # **Short Answer**
    **Yes. On Windows, when using the Microsoft C runtime (MSVCRT), argc
    is always guaranteed to be ò 1**, and ** argv[0] always exists**. However, **Windows itself does *not* guarantee what argv[0] contains** -
    only that the C runtime *treats* it as the program name.

    ---

    # **What Windows Guarantees vs. What the C Runtime Guarantees**

    ### **Microsoft C Runtime Guarantee**
    Microsoft?s documentation explicitly states:

    - *?Since the program name is considered an argument, the value of argc is at least one.?*

    So if your EXE is built with MSVC and uses the standard main or wmain , you can rely on:

    - argc >= 1
    - argv[0] is a valid null?terminated string
    - argv[argc] == NULL

    ### **MSVC Startup Code Behavior**
    MSVC startup code parses the command line and
    **always inserts the program name as argv[0] ** (quoted if needed).

    ---

    # **What Windows *Does Not* Guarantee**
    Windows itself does **not** enforce that the first token of the command line is the executable name. This is a convention, not a rule:

    - * By convention the module name ... is the first argument ... Note that this is
    only a convention and is not enforced in any way. *

    This means:

    - A caller can technically pass *anything* as the first token.
    - A process created via CreateProcess can have an arbitrary lpCommandLine .
    - argv[0] may not be the absolute path.
    - It may not even be a valid path at all.

    This is why portable code should not assume argv[0] is the executable path.

    ---

    # **Cross?Platform Note**
    The C standard does **not** guarantee that argv[0] contains the program name ? only that it exists.
    This is echoed in the search results:

    - * In short: No... this is more of a common convention than a strict rule. *

    ---

    # **Final Summary**
    | Question | Answer |
    |------------------------------------------------------|------------------------------------------|
    | **Does Windows guarantee argc >= 1 ?** | **Yes ? if using MSVC?s C runtime.** |
    | **Is argv[0] guaranteed to exist?** | **Yes ? with MSVC.** |
    | **Is argv[0] guaranteed to be the absolute path?** | **No.** |
    | **Does Windows enforce any of this?** | **No ? it?s the C runtime, not the OS.** |

    If you need the *actual* executable path, use:

    - GetModuleFileName(NULL, ...) (Windows API)

    ---

    https://learn.microsoft.com/en-us/cpp/c-language/argument-description?view=msvc-170&utm_source=copilot.com

    https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments?view=msvc-170&utm_source=copilot.com

    https://github-wiki-see.page/m/johnstevenson/winbox-args/wiki/How-Windows-parses-the-command-line?utm_source=copilot.com

    https://www.codegenes.net/blog/is-argv-0-name-of-executable-an-accepted-standard-or-just-a-common-convention/?utm_source=copilot.com

    When argv[0] Isn?t the Executable Name

    4.1 Invocation via exec Functions
    4.2 Symbolic Links
    4.3 Shell Scripts and Aliases
    4.4 Debuggers, Emulators, and Special Environments

    ********** End CoPilot Answer ************

    So is that a Yes or No?

    My C compiler calls __getmainargs() in msvcrt.dll to get argc/argv.

    __getmainargs() is also imported by programs compiled with Tiny C, and
    also with gcc 14.x from winlibs.com. (I assume it is actually called for
    the same purpose.)

    The specs for __getmainargs() say that the returned argc value is always
    = 1.

    (I doubt whether msvcrt.dll, which is present because so many programs
    rely on it, is what is used by MSVC-compiled appls, but you'd have to
    look inside such an app to check. EXEs inside \windows\system tend to
    import DLLs with names like "api-ms-win...".)

    In any case, it is easy enough to do a check on argc's value in your applications. (And on Windows, if it is 0 and you really need the path,
    you can get it with GetModuleFileNameA().)

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Paul@3:633/10 to All on Wednesday, December 31, 2025 15:07:02
    On Wed, 12/31/2025 1:42 PM, bart wrote:

    So is that a Yes or No?

    My C compiler calls __getmainargs() in msvcrt.dll to get argc/argv.

    __getmainargs() is also imported by programs compiled with Tiny C, and also with gcc 14.x from winlibs.com. (I assume it is actually called for the same purpose.)

    The specs for __getmainargs() say that the returned argc value is always >= 1.

    (I doubt whether msvcrt.dll, which is present because so many programs rely on it, is what is used by MSVC-compiled appls, but you'd have to look inside such an app to check. EXEs inside \windows\system tend to import DLLs with names like "api-ms-win...".)

    In any case, it is easy enough to do a check on argc's value in your applications. (And on Windows, if it is 0 and you really need the path, you can get it with GetModuleFileNameA().)

    The answer says "with MSVC". And your usage of msvcrt.dll likely applies
    to that statement.

    If you wrote your own version of a runtime msvcrt.dll then the answer could be no or maybe.

    I think if you're sufficiently clever, you can break that. But for
    the most part, lots of regular/lazy programming efforts will be guaranteeing
    a good result. I've used the argv[0] to determine the role of a program (encoder or decoder mode), and I'm just a very bad hobby programmer.

    Windows is pretty careless with metadata. In twenty years of watching Windows, I watched a program lose its name, and also one which had no parent. I thought when a program lost a parent that System() would own it. But when I checked, not even System was the parent. The parent was nothing. And Windows seemingly does not kill items malformed in that way. (The root cause may have been a RAM error, but I cannot be sure.)

    If you look in Task Manager in W10/W11, you cannot see Memory Compressor.
    If you use tasklist /V in a Terminal, then you can see it. That is just so you can contrast that with the behavior of Task Manager. And if you use Sysinternals (bought by Microsoft) Process Explorer utility, if you check Properties on Memory Compressor (even as administrator), no metadata is visible and the status says something about a necessary device is not responding.
    As if someone launched that in a particular way so it would be orphaned on purpose.

    But this is Windows for you. That's how you do things there.

    Paul


    Paul

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Wednesday, December 31, 2025 22:18:30
    On Wed, 31 Dec 2025 18:42:45 +0000
    bart <bc@freeuk.com> wrote:

    On 31/12/2025 17:30, Paul wrote:
    On Tue, 12/30/2025 10:37 PM, Keith Thompson wrote:
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 02:01:55 -0000 (UTC), Michael Sanders wrote:
    *ISO C (C17 / C23)*:

    C17, 5.1.2.2.1 "Program startup"

    The value of argc shall be nonnegative.

    argv[argc] shall be a null pointer.

    If the value of argc is greater than zero, the array members
    argv[0] through argv[argc?1] inclusive shall contain pointer
    s to
    strings which are given implementation-defined values.

    ...

    What say you?

    Clearly on Windows, there are no guarantees about argc contains,
    so you shouldn?t be relying on it.

    That's not clear. Linux (since 2022) guarantees argc>=1. I don't
    know whether Windows makes a similar guarantee, but it's entirely
    plausible that it could.

    But not all systems guarantee argc>=1, so any portable code
    shouldn't make assumptions beyond what's guaranteed by ISO C.


    The Windows guarantee is with MSVC, according to this answer.

    ********** CoPilot Question **********

    Does the Windows operating system guarantee that argc >= 1 for an
    EXE program ?

    argv[0] usually contains the program absolute path.

    ********** CoPilot Answer ************

    Here?s the clear, standards?grounded, Windows?s
    pecific answer
    you?re looking for ? with citations from the search res
    ults.

    # **Short Answer**
    **Yes. On Windows, when using the Microsoft C runtime (MSVCRT), argc
    is always guaranteed to be ò 1**, and ** argv[0] always
    exists**. However, **Windows itself does *not* guarantee what
    argv[0] contains** - only that the C runtime *treats* it as the
    program name.

    ---

    # **What Windows Guarantees vs. What the C Runtime Guarantees**

    ### **Microsoft C Runtime Guarantee**
    Microsoft?s documentation explicitly states:

    - *?Since the program name is considered an argument, the value
    of
    argc is at least one.?*

    So if your EXE is built with MSVC and uses the standard main or
    wmain , you can rely on:

    - argc >= 1
    - argv[0] is a valid null?terminated string
    - argv[argc] == NULL

    ### **MSVC Startup Code Behavior**
    MSVC startup code parses the command line and
    **always inserts the program name as argv[0] ** (quoted if
    needed).

    ---

    # **What Windows *Does Not* Guarantee**
    Windows itself does **not** enforce that the first token of the
    command line is the executable name. This is a convention, not a
    rule:

    - * By convention the module name ... is the first argument ...
    Note that this is only a convention and is not enforced in any way.
    *

    This means:

    - A caller can technically pass *anything* as the first token.
    - A process created via CreateProcess can have an arbitrary
    lpCommandLine .
    - argv[0] may not be the absolute path.
    - It may not even be a valid path at all.

    This is why portable code should not assume argv[0] is the
    executable path.

    ---

    # **Cross?Platform Note**
    The C standard does **not** guarantee that argv[0] contains the
    program name ? only that it exists. This is echoed in the search
    results:

    - * In short: No... this is more of a common convention than a
    strict rule. *

    ---

    # **Final Summary**
    | Question | Answer
    | |------------------------------------------------------|---------------
    ---------------------------|
    | **Does Windows guarantee argc >= 1 ?** | **Yes ?
    ? if
    using MSVC?s C runtime.** | | **Is argv[0] guaranteed to
    exist?** | **Yes ? with MSVC.**
    | | **Is argv[0] guaranteed to be the absolute path?** | **No.**
    | | **Does Windows enforce any of
    this?** | **No ? it?s the C runtime, not
    the OS.** |

    If you need the *actual* executable path, use:

    - GetModuleFileName(NULL, ...) (Windows API)

    ---

    https://learn.microsoft.com/en-us/cpp/c-language/argument-description?v
    iew=msvc-170&utm_source=copilot.com

    https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line
    -arguments?view=msvc-170&utm_source=copilot.com

    https://github-wiki-see.page/m/johnstevenson/winbox-args/wiki/How-Windo
    ws-parses-the-command-line?utm_source=copilot.com

    https://www.codegenes.net/blog/is-argv-0-name-of-executable-an-accepted
    -standard-or-just-a-common-convention/?utm_source=copilot.com

    When argv[0] Isn?t the Executable Name

    4.1 Invocation via exec Functions
    4.2 Symbolic Links
    4.3 Shell Scripts and Aliases
    4.4 Debuggers, Emulators, and Special Environments

    ********** End CoPilot Answer ************

    So is that a Yes or No?

    My C compiler calls __getmainargs() in msvcrt.dll to get argc/argv.

    __getmainargs() is also imported by programs compiled with Tiny C,
    and also with gcc 14.x from winlibs.com. (I assume it is actually
    called for the same purpose.)

    The specs for __getmainargs() say that the returned argc value is
    always
    = 1.

    (I doubt whether msvcrt.dll, which is present because so many
    programs rely on it, is what is used by MSVC-compiled appls, but
    you'd have to look inside such an app to check. EXEs inside
    \windows\system tend to import DLLs with names like "api-ms-win...".)

    In any case, it is easy enough to do a check on argc's value in your applications. (And on Windows, if it is 0 and you really need the
    path, you can get it with GetModuleFileNameA().)


    I experimented a little with CreateProcess() in caller (parent) and GetCommandLine() in callee (child). It seems that [under Windows] it is impossible to pass empty command line to child process.
    It makes no difference whether lpCommandLine argument of CreateProcess()
    call is NULL or "". In both cases the OS fills command line of the child
    with copy of lpApplicationName parameter.
    What *is* possible is passing of command line parameter that contains
    one or several white spaces. How compiler/start up code interprets such
    command line depends on specific compiler/start up code.
    If, like in your case, start up code is borrowed from Microsoft, then
    such command line is interpreted as (argc = 1; argv[0] = ""; argv[1] =
    NULL). I would guess that any start up code that is based on CommandLineToArgvW() syscall will deliver the same result.
    Of course, there are other possible choices as well. As mentioned up
    thread, as far as C Standard is concerned, argc=0 is also legal. But
    not using Microsoft's utilities sounds like plenty of extra work for non-obvious gain.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, December 31, 2025 20:51:41
    On Wed, 31 Dec 2025 15:15:02 +0200, Michael S wrote:

    ... using exec() in caller sounds like a bad idea. It just not how
    these systems work and not how people write programs on them.

    I don?t think I?ve used exec() on its own without fork() much, but it
    is quite common to do fork() without exec(). That?s another thing that
    I suspect non-*nix systems don?t handle very well.

    I'd implement caller with spawn(). I suppose that even on POSIX it
    is more idiomatic.

    Do you mean posix_spawn(3)?
    <https://manpages.debian.org/posix_spawn(3)>

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, December 31, 2025 20:52:59
    On Wed, 31 Dec 2025 15:29:09 +0200, Michael S wrote:

    On Wed, 31 Dec 2025 03:10:52 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    How did you come to this conclusion?

    The fact that the C spec says so. Is there any standard on Windows for
    how different C compilers are supposed to handle argc/argv?

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Wednesday, December 31, 2025 20:55:59
    On Wed, 31 Dec 2025 18:42:45 +0000, bart wrote:

    In any case, it is easy enough to do a check on argc's value in your applications. (And on Windows, if it is 0 and you really need the
    path, you can get it with GetModuleFileNameA().)

    Remember that, on *nix systems, the contents of argv are arbitrary and caller-specified. And none of them need bear any relation to the
    actual filename of the invoked executable.

    In fact, it is quite common for utilities to behave differently based
    on the name, as passed in argv[0], by which they are invoked.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From bart@3:633/10 to All on Wednesday, December 31, 2025 22:57:55
    On 31/12/2025 20:55, Lawrence D?Oliveiro wrote:
    On Wed, 31 Dec 2025 18:42:45 +0000, bart wrote:

    In any case, it is easy enough to do a check on argc's value in your
    applications. (And on Windows, if it is 0 and you really need the
    path, you can get it with GetModuleFileNameA().)

    Remember that, on *nix systems, the contents of argv are arbitrary and caller-specified. And none of them need bear any relation to the
    actual filename of the invoked executable.

    In fact, it is quite common for utilities to behave differently based
    on the name, as passed in argv[0], by which they are invoked.

    Yes, I do that all the time (especially from my other languages that
    also make use of msvcrt.dll).

    But, there is a difference between argv[0] and GetModuleFileName().

    The latter returns the full path of the executable (which also then
    allows you to pick up associated files in the same folder).

    argv[0] merely returns what was typed on the command line to invoke the application.

    So if someone types:

    C:\abc> prog

    it may run a prog.exe found in, say, c:\programs\myapp, and return the
    full path as "c:\programs\myapp\prog.exe".

    args[0] will give you only "prog"; good luck with that!

    I found out a few years ago that this useful funcion doesn't exist on Unix-like systems. You have to do it a more complicated way that may or
    may not work.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 15:00:24
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 30 Dec 2025 19:35:12 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    [...]
    For more information, see
    <https://github.com/Keith-S-Thompson/argv0>.

    If you are interested in behavior on non-POSIX systems, primarily
    Windows, but possibly others as well (e.g. VMS) then using exec() in
    caller sounds like a bad idea. It just not how these systems work and
    not how people write programs on them.
    Even when exec() *appears* to works in some environments (like
    msys2) it likely emulated by spawn() followed by exit().

    I'd implement caller with spawn(). I suppose that even on POSIX it is
    more idiomatic.

    If I were going to look into the behavior on Windows, I'd probably
    want to use Windows native features. (I tried my test on Cygwin,
    and the callee wasn't invoked.)

    Apparently the Windows way to invoke a program is CreateProcessA().
    But it takes the command line as a single string. There might not
    be a Windows-native way to exercise the kind of control over argc
    and argv provided by POSIX execve().

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 15:03:34
    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 31 Dec 2025 03:10:52 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:
    [...]
    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    How did you come to this conclusion?
    Keith's test appears to show the opposite - he was not able to convince
    the Windows system to call application with empty argv list.
    Of course, he tried only one way out of many, but knowing how native
    Windows system call works, it appears extremely likely that on Windows
    argc < 1 is impossible.

    To be clear, my test didn't show anything about Windows. I ran the test
    under Cygwin, not under native Windows.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 15:14:27
    Lawrence D?Oliveiro <ldo@nz.invalid> writes:
    On Wed, 31 Dec 2025 15:29:09 +0200, Michael S wrote:
    On Wed, 31 Dec 2025 03:10:52 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:
    Clearly on Windows, there are no guarantees about argc contains, so
    you shouldn?t be relying on it.

    How did you come to this conclusion?

    The fact that the C spec says so.

    You may well be correct, but I don't know how you reached that
    conclusion.

    Older Linux kernels make it possible to invoke a program with argc==0
    and argv[0]==NULL. Newer Linux kernels have a modified execve() that guarantees argc==1 and argv[0]!=NULL. NetBSD still permits argc==0.

    So some Unix-like systems (try to) guarantee argc>0, and some do not.

    It's entirely possible that Windows goes beyond the ISO C
    requirements and explicitly or implicitly guarantees argc>0.
    It's also entirely possible that it doesn't. Do you have any
    concrete information one way or the other

    Is there any standard on Windows for
    how different C compilers are supposed to handle argc/argv?

    That's a good question, and I don't know the answer.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 15:17:22
    scott@slp53.sl.home (Scott Lurndal) writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    [...]
    That's not clear. Linux (since 2022) guarantees argc>=1.

    Does it? That seems to be up to the shell, since the exec()
    manual pages on the latest Fedora Core release don't indicate
    that argv[0] must be initialized or that argc be greater than zero.

    As I understand it, all the exec() functions go through the execve()
    system call. In 2022, the Linux kernel execve() implementation was
    modified to guarantee that argc>0 and argv[0]!=NULL in the invoked
    program. A shell presumably can't bypass that.

    commit dcd46d897adb70d63e025f175a00a89797d31a43
    Author: Kees Cook <kees@kernel.org>
    Date: 2022-01-31 16:09:47 -0800

    exec: Force single empty string when argv is empty

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 15:29:15
    Paul <nospam@needed.invalid> writes:
    [...]
    # **Cross?Platform Note**
    The C standard does **not** guarantee that argv[0] contains the
    program name ? only that it exists.
    [...]

    That isn't quite correct, or is at least misleading. ISO C guarantees
    that argv[0] exists, but not that it points to a string. On some
    systems, it can contain be a null pointer.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From highcrew@3:633/10 to All on Thursday, January 01, 2026 00:31:32
    Hi,

    On 1/1/26 12:29 AM, Keith Thompson wrote:
    Paul <nospam@needed.invalid> writes:
    That isn't quite correct, or is at least misleading. ISO C guarantees
    that argv[0] exists, but not that it points to a string. On some
    systems, it can contain be a null pointer.

    I heard of this before.

    Is it just theoretical, or do we have actual systems where
    argv[0]==NULL? I never saw it happen in any modern operating system.

    --
    High Crew

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Thursday, January 01, 2026 01:45:48
    On Wed, 31 Dec 2025 15:00:24 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 30 Dec 2025 19:35:12 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    [...]
    For more information, see
    <https://github.com/Keith-S-Thompson/argv0>.

    If you are interested in behavior on non-POSIX systems, primarily
    Windows, but possibly others as well (e.g. VMS) then using exec()
    in caller sounds like a bad idea. It just not how these systems
    work and not how people write programs on them.
    Even when exec() *appears* to works in some environments (like
    msys2) it likely emulated by spawn() followed by exit().

    I'd implement caller with spawn(). I suppose that even on POSIX it
    is more idiomatic.

    If I were going to look into the behavior on Windows, I'd probably
    want to use Windows native features. (I tried my test on Cygwin,
    and the callee wasn't invoked.)


    That's likely because under Windows callee is named callee.exe.
    I didn't try on cygwin, but that was the reason of failure under msys2.
    Also, I am not sure if slash in the name is allowed. May be, backslash
    is required.

    Apparently the Windows way to invoke a program is CreateProcessA().
    But it takes the command line as a single string. There might not
    be a Windows-native way to exercise the kind of control over argc
    and argv provided by POSIX execve().


    Yes, some tricky combinations easily possible under POSIX are hard to
    achieve under Windows. The result could depend on exact implementation
    of parsing of command line in C start up code. May be, some combinations
    are even impossible, although right now I can not think out an
    example.

    But that was not my point. My point was that analog of exec() family
    does not exist in Windows (or VMS). Even if it appears to exist that
    just means that your environment somehow fooling you. The PID of child
    is not the same as parent's.
    So, if you want cross-platform test, it makes more sense to use spawn()
    family. It does not look like your test will be any more complicated
    with spawn() and as a free benefit you can print some info of
    interest in the parent process after after spawn() call.

    However I was wrong in my suggestion. I didn't realize that spawn
    functions under Windows and their POSIX equivalents have different names
    and different order of arguments.
    So, I take my suggestion back.







    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 16:00:45
    bart <bc@freeuk.com> writes:
    [...]
    argv[0] merely returns what was typed on the command line to invoke the application.

    So if someone types:

    C:\abc> prog

    it may run a prog.exe found in, say, c:\programs\myapp, and return the full path as
    "c:\programs\myapp\prog.exe".

    args[0] will give you only "prog"; good luck with that!
    [...]

    That's typically how it works, but it's not guaranteed.

    If a program is invoked from a shell on a Unix-like system, the
    shell will use something like fork() and one of the exec() functions,
    and will typically (perhaps always?) arrange for the new process's
    argv[0] to point to a copy of the program name given on the shell
    command line. (Programs that behave differently depending on the
    string pointed to by argv[0] are typically invoked via symbolic
    links, so for example vi and view might be names for the same
    executable.)

    But there are a number of other ways to invoke programs. In the
    example I posted, a C program calls execve() directly, and sets up
    argc and argv in a way that a shell would never do.

    For safety, any program should safely handle being invoked
    with unusual arguments -- especially any program with extra
    privileges. For simplicity, it could simply abort if argc==0
    and/or argv[0]==NULL.

    Similar considerations probably apply on Windows, though it seems that
    Windows tries to guarantee argc>1 and argv[0]!=NULL.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 16:05:19
    highcrew <high.crew3868@fastmail.com> writes:
    On 1/1/26 12:29 AM, Keith Thompson wrote:
    Paul <nospam@needed.invalid> writes:
    That isn't quite correct, or is at least misleading. ISO C guarantees
    that argv[0] exists, but not that it points to a string. On some
    systems, it can contain be a null pointer.

    I heard of this before.

    Is it just theoretical, or do we have actual systems where
    argv[0]==NULL? I never saw it happen in any modern operating system.

    Some systems (try to) guarantee that argv[0] points to a string, which
    may or may not be the name of the program. But there are ways, on some systems, to invoke a program with argc==0 and argv[0]==NULL.

    For details see here (I've recently made some updates).

    https://github.com/Keith-S-Thompson/argv0

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, December 31, 2025 16:34:44
    Michael S <already5chosen@yahoo.com> writes:
    On Wed, 31 Dec 2025 15:00:24 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    [...]
    If I were going to look into the behavior on Windows, I'd probably
    want to use Windows native features. (I tried my test on Cygwin,
    and the callee wasn't invoked.)

    That's likely because under Windows callee is named callee.exe.
    I didn't try on cygwin, but that was the reason of failure under msys2.
    Also, I am not sure if slash in the name is allowed. May be, backslash
    is required.

    No, that's definitely not it. Cygwin emulates a Unix-like system
    on top of Windows. It creates executables with a ".exe" suffix,
    but plays some tricks so that "foo.exe" also looks like "foo".
    Also, Cygwin uses "/" as a directory separator. When I modified
    the caller program to set argv[0], it worked correctly.

    I've updated the caller to show the result of execve() (which
    normally doesn't return). It returns -1 to indicate an error and
    sets errno to 7 (E2BIG, Argument list too long) -- which is a bit
    odd, but there's no E2SMALL code.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, January 01, 2026 01:03:16
    On Wed, 31 Dec 2025 22:57:55 +0000, bart wrote:

    But, there is a difference between argv[0] and GetModuleFileName().

    So the latter cannot be used as a simple substitute for the former, as
    you might have led us to believe.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Mike Terry@3:633/10 to All on Thursday, January 01, 2026 02:01:29
    On 31/12/2025 23:00, Keith Thompson wrote:
    Michael S <already5chosen@yahoo.com> writes:
    On Tue, 30 Dec 2025 19:35:12 -0800
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    [...]
    For more information, see
    <https://github.com/Keith-S-Thompson/argv0>.

    If you are interested in behavior on non-POSIX systems, primarily
    Windows, but possibly others as well (e.g. VMS) then using exec() in
    caller sounds like a bad idea. It just not how these systems work and
    not how people write programs on them.
    Even when exec() *appears* to works in some environments (like
    msys2) it likely emulated by spawn() followed by exit().

    I'd implement caller with spawn(). I suppose that even on POSIX it is
    more idiomatic.

    If I were going to look into the behavior on Windows, I'd probably
    want to use Windows native features. (I tried my test on Cygwin,
    and the callee wasn't invoked.)

    Apparently the Windows way to invoke a program is CreateProcessA().
    But it takes the command line as a single string. There might not
    be a Windows-native way to exercise the kind of control over argc
    and argv provided by POSIX execve().

    On Windows there is a command-line provided to applications via GetCommandLine() api. This is a
    single zero-terminated string. There is no mention of the possibility of GetCommandLine returning
    NULL.

    Windows (and in general non-*nix OS's) does not have a concept of processes having a list of strings
    as their basic start up mechanism. [Windows processes have an environment strings block, similar to
    *nix and used in the same way, but the "command line" is just a string...]

    Windows views parsing of the command-line string to be in the application domain, I guess. The MSVC
    compiler provides console-mode applications with the usual (argc, argv) but the MSVC application
    start-up code does this rather than the OS. For GUI-mode apps, MSVC provides a different interface
    to the user entry point. (Of course, if the app wants the command-line it can call the Windows api
    to get it, and if it wants command-line tokens it can parse it itself, or call CommandLineToArgv()
    api which is part of the shell api and replicates MSVC startup behaviour...)


    Mike.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, January 01, 2026 02:29:59
    On Thu, 1 Jan 2026 02:01:29 +0000, Mike Terry wrote:

    On Windows there is a command-line provided to applications via GetCommandLine() api. This is a single zero-terminated string.

    This idea comes from CP/M, which in turn copied it from the old DEC
    operating systems. This is a very primitive model, which never
    envisioned the more advanced kinds of things a Unix-style command line
    makes possible.

    Windows views parsing of the command-line string to be in the
    application domain, I guess.

    Consider a basic thing like quoting words on the command line, to
    allow the passing of arguments with spaces and other odd characters in
    them: with a raw command string, both ends have to agree on the same conventions for doing such things. Getting this wrong leads to great
    sadness.

    On *nix systems, there is no need for such conventions: the argv array
    will be passed literally from invoking program to invoking one, with
    no need for special quoting at all.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Thursday, January 01, 2026 07:23:06
    On Wed, 31 Dec 2025 16:34:44 -0800, Keith Thompson wrote:

    [...]

    It creates executables with a ".exe" suffix,
    but plays some tricks so that "foo.exe" also looks like "foo".

    Small aside... Minus the suffix, path in order of search
    is (if i recall correctly):

    1. an associated 'opener' if any (can be defined by associating
    suffix .foo with notepad.exe or whatever, also inherits the
    calling app's icon)

    2. in memory 'alias' via script/batch (set var=foo)

    3. current folder

    4. system path

    but... this also depends on %COMSPEC% ($SHELL in Windows) typically:

    powershell.exe
    cmd.exe
    command.exe
    user defined (like perl.exe for .pl or "busybox sh" for .sh)

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Thursday, January 01, 2026 07:32:34
    On Wed, 31 Dec 2025 09:37:08 -0000 (UTC), Lawrence D?Oliveiro wrote:

    Are there any standards for how C argc/argv are supposed to behave on Windows?

    Good question, some more ways to open things (that I know of),
    see 2nd example for 'sort of' argc/argv...

    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <shellapi.h>

    int open_app(const wchar_t *exe_or_path) {
    HINSTANCE r = ShellExecuteW(NULL, L"open", exe_or_path, NULL, NULL, SW_SHOWNORMAL);
    return ((INT_PTR)r > 32) ? 0 : -1;
    }

    open_app(L"notepad.exe");
    open_app(L"C:\\Windows\\System32\\calc.exe");

    or...

    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <wchar.h>

    int launch_app(const wchar_t *cmdline) {
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof si);
    ZeroMemory(&pi, sizeof pi);
    si.cb = sizeof si;

    /* CreateProcess *may modify the buffer */
    wchar_t buf[1024];
    wcsncpy(buf, cmdline, 1023);
    buf[1023] = L'\0';

    if (!CreateProcessW(
    NULL, // application name (NULL = parse from cmdline)
    buf, // command line (MUTABLE) <--
    NULL, NULL, // process/thread security
    FALSE, // inherit handles
    0, // creation flags
    NULL, // environment
    NULL, // working directory
    &si,
    &pi))
    return -1;

    /* fire-and-forget */
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return 0;
    }

    launch_app(L"notepad.exe C:\\temp\\notes.txt");
    launch_app(L\"\"C:\\Program Files\\VideoLAN\\VLC\\vlc.exe\" --fullscreen video.mp4\");

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From bart@3:633/10 to All on Thursday, January 01, 2026 14:05:29
    On 01/01/2026 01:03, Lawrence D?Oliveiro wrote:
    On Wed, 31 Dec 2025 22:57:55 +0000, bart wrote:

    But, there is a difference between argv[0] and GetModuleFileName().

    So the latter cannot be used as a simple substitute for the former, as
    you might have led us to believe.


    It depends on your needs. If you need to know exactly what was typed,
    then you use GetCommandLine and extract the first part of it.

    Or you just use __getmainargs. Or argv[0] if available.

    However, I was responding to this:

    LD'O:
    In fact, it is quite common for utilities to behave differently based
    on the name, as passed in argv[0], by which they are invoked.

    And previously I'd said this:

    (And on Windows, if it is 0 and you really need the path, you can get
    it with GetModuleFileNameA().)

    At that point I'd forgotten that GetModuleFileName gives you more
    information than argv[0], so you'd to extract it. But you'd have to do
    that anyway to clean up the input: somebody may have typed c:\abc\.\.\.\.\.\ProG

    So I wasn't misleading anybody.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, January 01, 2026 19:02:49
    On Thu, 1 Jan 2026 07:32:34 -0000 (UTC), Michael Sanders wrote:

    On Wed, 31 Dec 2025 09:37:08 -0000 (UTC), Lawrence D?Oliveiro wrote:

    Are there any standards for how C argc/argv are supposed to behave
    on Windows?

    Good question, some more ways to open things (that I know of), see
    2nd example for 'sort of' argc/argv...

    [examples omitted]

    All those are at the sending end. But what would C code see at the
    receiving end?

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, January 01, 2026 19:03:47
    On Thu, 1 Jan 2026 14:05:29 +0000, bart wrote:

    On 01/01/2026 01:03, Lawrence D?Oliveiro wrote:

    On Wed, 31 Dec 2025 22:57:55 +0000, bart wrote:

    But, there is a difference between argv[0] and
    GetModuleFileName().

    So the latter cannot be used as a simple substitute for the former,
    as you might have led us to believe.

    It depends on your needs.

    You neglected to mention that when offering the substitute before
    though, didn?t you?

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Thursday, January 01, 2026 19:20:08
    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC), Lawrence D?Oliveiro wrote:

    All those are at the sending end. But what would C code see at the
    receiving end?

    Opp, you're right. My bad (stuck function pointer h*ll at the moment...)

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Thursday, January 01, 2026 21:53:20
    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    On Thu, 1 Jan 2026 07:32:34 -0000 (UTC), Michael Sanders wrote:

    On Wed, 31 Dec 2025 09:37:08 -0000 (UTC), Lawrence D?Oliveiro w
    rote:

    Are there any standards for how C argc/argv are supposed to behave
    on Windows?

    Good question, some more ways to open things (that I know of), see
    2nd example for 'sort of' argc/argv...

    [examples omitted]

    All those are at the sending end. But what would C code see at the
    receiving end?

    The first three cases look very simple.

    1.
    argc=1
    argv[0]=notepad.exe
    argv[1]=NULL

    2.
    argc=1
    argv[0]=C:\Windows\System32\calc.exe
    argv[1]=NULL

    3.
    argc=2
    argv[0]=notepad.exe
    argv[1]=C:\temp\notes.txt
    argv[2]=NULL


    4th case does not look like a legal C code.
    It probably was screwed either by poster's news reader or by my
    news reader.




    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From bart@3:633/10 to All on Thursday, January 01, 2026 20:28:52
    On 01/01/2026 19:03, Lawrence D?Oliveiro wrote:
    On Thu, 1 Jan 2026 14:05:29 +0000, bart wrote:

    On 01/01/2026 01:03, Lawrence D?Oliveiro wrote:

    On Wed, 31 Dec 2025 22:57:55 +0000, bart wrote:

    But, there is a difference between argv[0] and
    GetModuleFileName().

    So the latter cannot be used as a simple substitute for the former,
    as you might have led us to believe.

    It depends on your needs.

    You neglected to mention that when offering the substitute before
    though, didn?t you?


    FFS, why are you always looking for some argument?

    Have the last word if you like. If it makes you happier, I will admit I
    was deliberately misleading and totally wrong.

    But about what, I don't know! FWIW, I first mentioned GetModuleFileName
    as a possibility when argv[0] was not available.

    So I now withdraw that suggestion. That means that if argv[0] isn't
    available, then you're fucked, since there are apparently no workarounds
    that would be 100% equivalent to what argv[0] would have provided.



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Thursday, January 01, 2026 23:50:00
    On Thu, 1 Jan 2026 21:53:20 +0200, Michael S wrote:

    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    All those are at the sending end. But what would C code see at the
    receiving end?

    The first three cases look very simple.

    Is there some spec in Windows which describes how that works?

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Friday, January 02, 2026 14:32:07
    On Thu, 1 Jan 2026 23:50:00 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    On Thu, 1 Jan 2026 21:53:20 +0200, Michael S wrote:

    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    All those are at the sending end. But what would C code see at the
    receiving end?

    The first three cases look very simple.

    Is there some spec in Windows which describes how that works?

    There is a spec that describes how that works in Microsoft's
    implementation. That implementation is available free of charge to
    other Windows compilers.
    If vendor of Windows 'C' compiler decided to implement different
    algorithm then nobody can stop him.

    Through the years you were told so, by different people, and shown
    the spec may be 100 times. But being the trolll you are, you continue
    to ask.

    Still, for the benefit of more sincere readers and also for myself, in
    order to have both pieces in one place: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-co mmandlinetoargvw https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arg uments


    More interesting and meaningful question is how to do the reverse.
    I.e. how to convert an argv[] array into flat form in a way that
    guarantees that CommandLineToArgvW() parses it back into original form?
    Is it even possible in general case or there exist limitations
    (ignoring, for sake of brevity, 2*15-1 size limit)?

    Microsoft certainly has reverse conversion implemented, e.g. here: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnv-ws pawnv

    But I am not aware of command line serialization part available as a
    library call in isolation from process creation part.

    I binged around and googled around, but all I was able to find was the
    name of the function that performs the work: __acrt_pack_wide_command_line_and_environment

    I was not able to find the source code of the function.

    [O.T.]
    I am sure that 15, 10 or even 5 years ago Google would give me link to
    the source in a second. Or, may be, 5 years ago Google already
    wouldn't, but Bing still would.
    But today both search engines are hopelessly crippled with AI and do not
    appear to actually search the web. Instead, the try to guess the
    answer I likely want to hear.
    [/O.T.]












    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Friday, January 02, 2026 16:18:39
    On Fri, 2 Jan 2026 14:32:07 +0200
    Michael S <already5chosen@yahoo.com> wrote:


    More interesting and meaningful question is how to do the reverse.
    I.e. how to convert an argv[] array into flat form in a way that
    guarantees that CommandLineToArgvW() parses it back into original
    form? Is it even possible in general case or there exist limitations (ignoring, for sake of brevity, 2*15-1 size limit)?

    Microsoft certainly has reverse conversion implemented, e.g. here: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnv-wspawnv


    Experimenting with _spawnv() shows that Microsoft made no effort in the direction of invertible serialization/de-serialization of argv[] lists.
    That is, as long as there are no double quotes, everything works as
    expected. But when there are double quotes in the original argv[] then
    more often than not they can't be passed exactly.

    An exact result of de-serialization in presence of unusually placed
    " characters depends on the version of the library.
    Very old versions, like those before UCRT or relatively new
    versions of UCRT, like one in VS2022, do not produce an exact
    inversion, but otherwise their results are reasonable. The version of
    the library supplied with UCRT variant of msys2 tools is much less
    reasonable. I'd rather characterize it as buggy.
    Frankly, I don't understand how it is possible. It leads me to believe
    that parsing routines in C RTL do not use system-provided parser and
    instead do parsing by themselves.




    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, January 02, 2026 20:46:47
    On Fri, 2 Jan 2026 14:32:07 +0200, Michael S wrote:

    Through the years you were told so, by different people, and shown
    the spec may be 100 times. But being the trolll you are, you
    continue to ask.

    Still, for the benefit of more sincere readers and also for myself,
    in order to have both pieces in one place: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
    https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments

    That second one begins with these words in large letters:

    ?MICROSOFT SPECIFIC?

    (Remember I was asking for a spec applicable to Windows generally.)

    Who?s trolling now?
    Who?s trolling now?

    (To the tune of ?Who?s sorry now?? etc)

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Friday, January 02, 2026 20:52:59
    On Fri, 2 Jan 2026 16:18:39 +0200, Michael S wrote:

    Experimenting with _spawnv() shows that Microsoft made no effort in the direction of invertible serialization/de-serialization of argv[] lists.
    That is, as long as there are no double quotes, everything works as
    expected. But when there are double quotes in the original argv[] then
    more often than not they can't be passed exactly.

    And every now and then, this kind of fudging can progress beyond
    regular inflammation sadness into the full-fledged tumour of a Windows
    security hole <https://web.archive.org/web/20240711101329/https://list.waikato.ac.nz/archives/list/wlug@list.waikato.ac.nz/message/NVHWSZP7QF7QKYJO2UCHGZC4ADWSNNS7/>.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Mike Terry@3:633/10 to All on Saturday, January 03, 2026 04:08:40
    On 02/01/2026 12:32, Michael S wrote:
    On Thu, 1 Jan 2026 23:50:00 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    On Thu, 1 Jan 2026 21:53:20 +0200, Michael S wrote:

    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    All those are at the sending end. But what would C code see at the
    receiving end?

    The first three cases look very simple.

    Is there some spec in Windows which describes how that works?

    There is a spec that describes how that works in Microsoft's
    implementation. That implementation is available free of charge to
    other Windows compilers.
    If vendor of Windows 'C' compiler decided to implement different
    algorithm then nobody can stop him.

    Through the years you were told so, by different people, and shown
    the spec may be 100 times. But being the trolll you are, you continue
    to ask.

    Still, for the benefit of more sincere readers and also for myself, in
    order to have both pieces in one place: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
    https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments


    In the long distant past I investigated how MSVC converts a command-line to its argc/argv input.
    There was an internal routine in the CRT startup code that did pretty much what we would expect, and
    I reversed engineered that for my code (or did I just copy the code? surely the former!). The MSVC
    code did not call CommandLineToArgvW in those days, but reading the description of that api it all
    sounds very familiar - the state flags for controlling "quoted/unquoted" text, even vs odd numbers
    of backslashes and all that.

    I didn't find it difficult to create command-line strings to call C programs, given what I wanted
    those programs to see as argv[n] with n>0. I think it was just a case of quoting all arguments,
    then applying quoting rules as docuemented for CommandLineToArgvW to handle nested quotes/backslashes.

    But I can see a sticky problem - the MSVC parsing for argv[0] was completely separate from thr main
    loop handling other arguments. The logic was considerably simplified, assuming that argv[0] was the
    path for the module being invoked. Since that is expected to be a valid file system path, the logic
    did not handle nested quotes etc.. I think the logic was just:

    - if 1st char is a DQUOTE, copy chars for argv[0] up to next DQUOTE or null terminator.
    (enclosing DQUOTE chars are not included)
    - else copy chars for argv[0] up to next whitespace or null terminator.
    (all chars are included, I think including DQUOTE should it occur)

    Given this, it would not be possible to create certain argv[0] strings containing quotes etc., and I
    understand that the likes of execve() allow that possibility. So I don't know what should happen
    for this case. E.g. I don't see there is a command-line that gives argv[0] the string "\" ". This
    was never a problem for me in practice.

    There would always be at least an argv[0] with this logic, so MSVC ensures argc>0 and argv[0] !=
    NULL. (Of course, MSVC is not "Windows". Various posters in this thread seem to be asking "what
    does /Windows/ do regarding argc/argv?" as though the OS is responsible for setting them.)


    More interesting and meaningful question is how to do the reverse.
    I.e. how to convert an argv[] array into flat form in a way that
    guarantees that CommandLineToArgvW() parses it back into original form?
    Is it even possible in general case or there exist limitations
    (ignoring, for sake of brevity, 2*15-1 size limit)?

    Yes, programmers need this if they need to create a process to invoke some utility program which
    will see particular argv parameters. Users are used to typing in command-lines as a string, e.g. at
    a console, so I suppose they don't normally need to think about the argv[] parsing; they can just
    build the required command-line and use that. (But it's a problem in the general case.)

    The argc/argv problem seemed easy enough in practice if we only need to handle the "real" arguments
    argv[n] with n>0. (Involving CMD.EXE introduced much worse complications, as you might imagine.
    But generally I always thought that MS wasn't really interested in /documenting/ how programmers
    should do things like this, in the same way they never bothered explaining exactly how CMD
    processing worked. Probably because it was forever changing!... Put another way, for many years
    they were really more focussed on admins clicking buttons in some GUI!)


    Microsoft certainly has reverse conversion implemented, e.g. here: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnv-wspawnv

    But I am not aware of command line serialization part available as a
    library call in isolation from process creation part.

    I binged around and googled around, but all I was able to find was the
    name of the function that performs the work: __acrt_pack_wide_command_line_and_environment

    I was not able to find the source code of the function.

    [O.T.]
    I am sure that 15, 10 or even 5 years ago Google would give me link to
    the source in a second. Or, may be, 5 years ago Google already
    wouldn't, but Bing still would.
    But today both search engines are hopelessly crippled with AI and do not appear to actually search the web. Instead, the try to guess the
    answer I likely want to hear.
    [/O.T.]

    I hear you on that! Also [O.T.] I used to have access to most of Windows source code as part of
    some Windows source code sharing program, so could have found answers to this sort of question with
    minimal effort. (My employer met the criteria based on number of Windows servers/desktops deployed.
    There were various hoops you had to jump through with contracts being regularly (re)signed by
    company board level directors and the likes. Wonder if they still do that... Anyway I'm long
    retired now.)


    Mike.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Saturday, January 03, 2026 04:39:39
    On Sat, 3 Jan 2026 04:08:40 +0000, Mike Terry wrote:

    The argc/argv problem seemed easy enough in practice if we only need
    to handle the "real" arguments argv[n] with n>0. (Involving CMD.EXE introduced much worse complications, as you might imagine. But
    generally I always thought that MS wasn't really interested in
    /documenting/ how programmers should do things like this, in the
    same way they never bothered explaining exactly how CMD processing
    worked. Probably because it was forever changing!... Put another
    way, for many years they were really more focussed on admins
    clicking buttons in some GUI!)

    After years -- decades -- of conditioning its users to be allergic to
    the command line, now suddenly the rise of Linux has made command
    lines cool again. Leaving Microsoft in an awkward position ...

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Saturday, January 03, 2026 14:24:12
    On Sat, 3 Jan 2026 04:39:39 -0000 (UTC), Lawrence D?Oliveiro wrote:

    After years -- decades -- of conditioning its users to be allergic to
    the command line, now suddenly the rise of Linux has made command
    lines cool again. Leaving Microsoft in an awkward position ...

    And telemetry... compulsory updates... ads all over the place...
    (even paid editions). I'd rather have a quite conversation with
    my OS[1] instead of an argument. Microsoft has gotten /very/
    predacious the last few years at least from my point of view.

    [1] CLI is good for that

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Saturday, January 03, 2026 20:38:42
    On Sat, 3 Jan 2026 04:08:40 +0000
    Mike Terry <news.dead.person.stones@darjeeling.plus.com> wrote:

    On 02/01/2026 12:32, Michael S wrote:
    On Thu, 1 Jan 2026 23:50:00 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    On Thu, 1 Jan 2026 21:53:20 +0200, Michael S wrote:

    On Thu, 1 Jan 2026 19:02:49 -0000 (UTC)
    Lawrence D?Oliveiro <ldo@nz.invalid> wrote:

    All those are at the sending end. But what would C code see at
    the receiving end?

    The first three cases look very simple.

    Is there some spec in Windows which describes how that works?

    There is a spec that describes how that works in Microsoft's implementation. That implementation is available free of charge to
    other Windows compilers.
    If vendor of Windows 'C' compiler decided to implement different
    algorithm then nobody can stop him.

    Through the years you were told so, by different people, and shown
    the spec may be 100 times. But being the trolll you are, you
    continue to ask.

    Still, for the benefit of more sincere readers and also for myself,
    in order to have both pieces in one place: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
    https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments


    In the long distant past I investigated how MSVC converts a
    command-line to its argc/argv input. There was an internal routine in
    the CRT startup code that did pretty much what we would expect, and I reversed engineered that for my code (or did I just copy the code?
    surely the former!). The MSVC code did not call CommandLineToArgvW
    in those days, but reading the description of that api it all sounds
    very familiar - the state flags for controlling "quoted/unquoted"
    text, even vs odd numbers of backslashes and all that.

    I didn't find it difficult to create command-line strings to call C
    programs, given what I wanted those programs to see as argv[n] with
    0. I think it was just a case of quoting all arguments, then
    applying quoting rules as docuemented for CommandLineToArgvW to
    handle nested quotes/backslashes.

    But I can see a sticky problem - the MSVC parsing for argv[0] was
    completely separate from thr main loop handling other arguments. The
    logic was considerably simplified, assuming that argv[0] was the path
    for the module being invoked. Since that is expected to be a valid
    file system path, the logic did not handle nested quotes etc.. I
    think the logic was just:

    - if 1st char is a DQUOTE, copy chars for argv[0] up to next DQUOTE
    or null terminator. (enclosing DQUOTE chars are not included)
    - else copy chars for argv[0] up to next whitespace or null
    terminator. (all chars are included, I think including DQUOTE should
    it occur)

    Given this, it would not be possible to create certain argv[0]
    strings containing quotes etc., and I understand that the likes of
    execve() allow that possibility. So I don't know what should happen
    for this case. E.g. I don't see there is a command-line that gives
    argv[0] the string "\" ". This was never a problem for me in
    practice.

    There would always be at least an argv[0] with this logic, so MSVC
    ensures argc>0 and argv[0] != NULL. (Of course, MSVC is not
    "Windows". Various posters in this thread seem to be asking "what
    does /Windows/ do regarding argc/argv?" as though the OS is
    responsible for setting them.)


    More interesting and meaningful question is how to do the reverse.
    I.e. how to convert an argv[] array into flat form in a way that
    guarantees that CommandLineToArgvW() parses it back into original
    form? Is it even possible in general case or there exist limitations (ignoring, for sake of brevity, 2*15-1 size limit)?

    Yes, programmers need this if they need to create a process to invoke
    some utility program which will see particular argv parameters.
    Users are used to typing in command-lines as a string, e.g. at a
    console, so I suppose they don't normally need to think about the
    argv[] parsing; they can just build the required command-line and use
    that. (But it's a problem in the general case.)


    I hoped that Microsoft's implementation of _spawnv() at least
    makes an effort at reverse transformation. But test shows that it
    does not. _spawnl() appears to do something very dumb - just concatenate
    all argv[] strings inserting one space character between parts.
    So, it has troubles not just with double quotes but even with spaces
    within arguments.


    The argc/argv problem seemed easy enough in practice if we only need
    to handle the "real" arguments argv[n] with n>0. (Involving CMD.EXE introduced much worse complications, as you might imagine. But
    generally I always thought that MS wasn't really interested in
    /documenting/ how programmers should do things like this, in the same
    way they never bothered explaining exactly how CMD processing worked.
    Probably because it was forever changing!... Put another way, for
    many years they were really more focussed on admins clicking buttons
    in some GUI!)


    To be fair, powershell exists for many more years than WinNt family was existing before emergence of powershell.
    The problem with it, at least IMHO, is a second system syndrome.
    command.com and to significant extent cmd.exe as well, seen as
    programming language was too weak and too primitive. With Powershell
    they went too far in the opposite direction - its rather powerfull, as programming language, but nott as simple at simple tasks as one expects
    from OS shell.
    So, considering that fewer and fewer people with programmer's attitude
    are employed as admins, it's no wonder that most of them are incapable
    to write powershell scripts by themselves. At best, they can cat&past.








    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Geoff@3:633/10 to All on Monday, January 05, 2026 20:00:26
    On Wed, 31 Dec 2025 15:14:27 -0800, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    It's entirely possible that Windows goes beyond the ISO C
    requirements and explicitly or implicitly guarantees argc>0.
    It's also entirely possible that it doesn't. Do you have any
    concrete information one way or the other

    https://learn.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Wednesday, January 07, 2026 07:39:08
    John McCue <jmclnx@gmail.com.invalid> writes:

    Michael Sanders <porkchop@invalid.foo> wrote:

    Is it incorrect to use 0 (zero) to seed srand()?

    int seed = (argc >= 2 && strlen(argv[1]) == 9)
    ? atoi(argv[1])
    : (int)(time(NULL) % 900000000 + 100000000);

    srand(seed);

    I like to just read /dev/urandom when I need a random
    number. Seem easier and more portable across Linux &
    the *BSDs.

    int s;
    read(fd, &s, sizeof(int));

    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Wednesday, January 07, 2026 07:46:40
    Michael S <already5chosen@yahoo.com> writes:

    [regarding rand() and srand()]

    Pay attention that C Standard only requires for the same seed to always produces the same sequence. There is no requirement that different
    seeds have to produce different sequences.
    So, for generator in your example, implementation like below would be
    fully legal. Personally, I wouldn't even consider it as particularly
    poor quality:

    void srand(unsigned seed ) { init = seed | 1;}

    It seems better to do, for example,

    void srand(unsigned seed ) { init = seed - !seed;}


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Wednesday, January 07, 2026 07:50:09
    antispam@fricas.org (Waldek Hebisch) writes:

    [...]
    There is a paper "PCG: A Family of Simple Fast Space-Efficient
    Statistically Good Algorithms for Random Number Generation"
    by M. O?Neill where she gives a family of algorithms and runs
    several statistical tests against known algorithms. Mersenne
    Twister does not look good in tests. If you have enough (128) bits
    LCGs do pass tests. A bunch of generators with 64-bit state also
    passes tests. So the only reason to prefer Mersenne Twister is
    that it is implemented in available libraries. Otherwise it is
    not so good, have large state and needs more execution time
    than alternatives.

    Interesting paper. Thank you.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Wednesday, January 07, 2026 18:14:14
    On Wed, 07 Jan 2026 07:46:40 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    [regarding rand() and srand()]

    Pay attention that C Standard only requires for the same seed to
    always produces the same sequence. There is no requirement that
    different seeds have to produce different sequences.
    So, for generator in your example, implementation like below would
    be fully legal. Personally, I wouldn't even consider it as
    particularly poor quality:

    void srand(unsigned seed ) { init = seed | 1;}

    It seems better to do, for example,

    void srand(unsigned seed ) { init = seed - !seed;}


    Yes, it is better.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Wednesday, January 07, 2026 08:41:25
    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 23 Dec 2025 17:54:05 -0000 (UTC)
    antispam@fricas.org (Waldek Hebisch) wrote:
    [...]
    There is a paper "PCG: A Family of Simple Fast Space-Efficient
    Statistically Good Algorithms for Random Number Generation"
    by M. O?Neill where she gives a family of algorithms and runs
    several statistical tests against known algorithms. Mersenne
    Twister does not look good in tests. If you have enough (128) bits
    LCGs do pass tests. A bunch of generators with 64-bit state also
    passes tests. So the only reason to prefer Mersenne Twister is
    that it is implemented in available libraries. Otherwise it is
    not so good, have large state and needs more execution time
    than alternatives.

    I don't know. Testing randomness is complicated matter.
    How can I be sure that L'Ecuyer and Simard's TestU01 suite tests
    things that I personally care about and that it does not test
    things that are of no interest for me? Especially, the latter.

    Do you think any of the tests in the TestU01 suite are actually counter-indicated? As long as you don't think any TestU01 test
    makes things worse, there is no reason not to use all of them.
    You are always free to disregard tests you don't care about.

    Also, the TestU01 suit is made for generators with 32-bit output.
    M. O'Neill used ad hoc technique to make it applicable to
    generators with 64-bit output. Is this technique right? Or may
    be it put 64-bit PRNG at unfair disadvantage?

    As long as the same mapping is applied to all 64-bit PRNGs under
    consideration I don't see a problem. The point of the test is to
    compare PRNGs, not to compare test methods. If someone thinks a
    different set of tests is called for they are free to run them.

    Besides, I strongly disagree with at least one assertion made by
    O'Neill: "While security-related applications should use a secure
    generator, because we cannot always know the future contexts in
    which our code will be used, it seems wise for all applications to
    avoid generators that make discovering their entire internal state
    completely trivial."
    No, I know exactly what I am doing/ I know exactly that for my
    application easy discovery of complete state of PRNG is not a
    defect.

    You and she are talking about different things. You are talking
    about choosing a PRNG to be used only by yourself. She is talking
    about choosing a PRNG to be made available to other people without
    knowing who they are or what their needs are. In the second case
    it's reasonable to raise the bar for the set of criteria that need
    to be met.

    Anyway, even if I am skeptical about her criticism of popular PRNGs, intuitively I agree with the constructive part of the article - medium-quality PRNG that feeds medium quality hash function can
    potentially produce very good fast PRNG with rather small internal
    state.

    After looking at one of the example PCG generators, I would
    describe it as a medium-quality PRNG that feeds a low-quality
    hash. The particular combination I looked at produced good
    results, but it isn't clear which combinations of PRNG and
    hash would do likewise.

    On related note, I think that even simple counter fed into high
    quality hash function (not cryptographically high quality, far
    less than that) can produce excellent PRNG with even smaller
    internal state. But not very fast one. Although the speed
    depends on specifics of used computer. I can imagine computer
    that has low-latency Rijndael128 instruction. On such computer,
    running counter through 3-4 rounds of Rijndael ill produce very
    good PRNG that is only 2-3 times slower than, for example, LCG
    128/64.

    I think the point of her paper where she talks about determining
    how much internal state is needed is to measure the efficacy of
    the PRNG, not to try to reduce the amount of state needed. Based
    on my own experience with various PRNGs I think it's a mistake to
    try to minimize the amount of internal state needed. My own rule
    of thumb is to allow at least a factor of four: for example, a
    PRNG with a 32-bit output should have at least 128 bits of state.
    My latest favorite has 256 bits of state to produce 32-bit
    outputs (and so might also do well to produce 64-bit outputs, but
    I haven't tested that).

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Wednesday, January 07, 2026 13:54:21
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    John McCue <jmclnx@gmail.com.invalid> writes:
    Michael Sanders <porkchop@invalid.foo> wrote:
    Is it incorrect to use 0 (zero) to seed srand()?

    int seed = (argc >= 2 && strlen(argv[1]) == 9)
    ? atoi(argv[1])
    : (int)(time(NULL) % 900000000 + 100000000);

    srand(seed);

    I like to just read /dev/urandom when I need a random
    number. Seem easier and more portable across Linux &
    the *BSDs.

    int s;
    read(fd, &s, sizeof(int));

    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    And neither is the non-conforming rand() on OpenBSD.

    The rand(1) man page on OpenBSD 7.8 says:

    Standards insist that this interface return deterministic
    results. Unsafe usage is very common, so OpenBSD changed the
    subsystem to return non-deterministic results by default.

    To satisfy portable code, srand() may be called to initialize
    the subsystem. In OpenBSD the seed variable is ignored,
    and strong random number results will be provided from
    arc4random(3). In other systems, the seed variable primes a
    simplistic deterministic algorithm.

    It does provide an srand_deterministic() function that behaves the way
    srand() is supposed to.

    And a program that calls rand() produces a link-time warning, even
    though OpenBSD's rand() *doesn't* return deterministic values.

    ld: warning: rand_test.c(rand_test.o:(main)): warning: rand() may return deterministic values, is that what you want?

    (In a similarly questionable decision, OpenBSD's printf triggers a
    SIGABRT signal if the format string uses "%n".)

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Thursday, January 08, 2026 01:06:01
    On Wed, 07 Jan 2026 08:41:25 -0800
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Michael S <already5chosen@yahoo.com> writes:

    On Tue, 23 Dec 2025 17:54:05 -0000 (UTC)
    antispam@fricas.org (Waldek Hebisch) wrote:
    [...]
    There is a paper "PCG: A Family of Simple Fast Space-Efficient
    Statistically Good Algorithms for Random Number Generation"
    by M. O?Neill where she gives a family of algorithms and runs
    several statistical tests against known algorithms. Mersenne
    Twister does not look good in tests. If you have enough (128) bits
    LCGs do pass tests. A bunch of generators with 64-bit state also
    passes tests. So the only reason to prefer Mersenne Twister is
    that it is implemented in available libraries. Otherwise it is
    not so good, have large state and needs more execution time
    than alternatives.

    I don't know. Testing randomness is complicated matter.
    How can I be sure that L'Ecuyer and Simard's TestU01 suite tests
    things that I personally care about and that it does not test
    things that are of no interest for me? Especially, the latter.

    Do you think any of the tests in the TestU01 suite are actually counter-indicated? As long as you don't think any TestU01 test
    makes things worse, there is no reason not to use all of them.
    You are always free to disregard tests you don't care about.


    Except that it's difficult psychologically.
    The batteries of test gains position of of authority in your mind.
    Well, may be, you specifically are resistant, but I am not. Nor is
    Melissa O'Nail, it seems.

    To illustrate my point, I will tell you the story about myself.
    Sort of confession.
    If you had read the rest of this thread (or paid attention to
    finer details in the article of O'Nail) then you already know that
    mt19937 consistently fails in scomp_LinearComp() subtest of Crush and
    BigCrush batteries of Test01. As reported, I "fixed" it by skipping
    every 19936th word of mt19937 output. This particular "fix" is benign.
    I am sure that it does not make output of generator less random. The
    only impact is a bit of slowness, because of the need to manage yet
    another modulo counter.
    What I did not tell so far is that I tried another "fix". I added
    leakage during mt state update. It means that periodically I
    forced two LS bits of newly generated state word to be '01', without
    affecting the word that goes to tampering and then to output.
    And according to Test01 it worked! Flew through all batteries!
    Luckily, I was sufficiently self-conscious to understand that I don't understand nearly enough about algebra of Galois fields to predict all consequences of my modification. But that's me. I know few people that
    are less aware of their limitations.

    Also, the TestU01 suit is made for generators with 32-bit output.
    M. O'Neill used ad hoc technique to make it applicable to
    generators with 64-bit output. Is this technique right? Or may
    be it put 64-bit PRNG at unfair disadvantage?

    As long as the same mapping is applied to all 64-bit PRNGs under consideration I don't see a problem. The point of the test is to
    compare PRNGs, not to compare test methods. If someone thinks a
    different set of tests is called for they are free to run them.


    But Melissa, following advice of L'Ecuyer, and me, following advice of
    Melissa, tested 64-bit generators three times - LSW then MSW, only LSW
    and only MSW, thus putting them under trice more serious scrutiny than
    32-bit counterparts.

    Besides, I strongly disagree with at least one assertion made by
    O'Neill: "While security-related applications should use a secure generator, because we cannot always know the future contexts in
    which our code will be used, it seems wise for all applications to
    avoid generators that make discovering their entire internal state completely trivial."
    No, I know exactly what I am doing/ I know exactly that for my
    application easy discovery of complete state of PRNG is not a
    defect.

    You and she are talking about different things. You are talking
    about choosing a PRNG to be used only by yourself. She is talking
    about choosing a PRNG to be made available to other people without
    knowing who they are or what their needs are. In the second case
    it's reasonable to raise the bar for the set of criteria that need
    to be met.


    No, this part of her article is a mistake, plain and simple.
    He even sort of admitted it couple of years later in her blogg.
    In reality, we either need secure PRNG or do not need secure PRNG.
    There is no middle ground of "more or less secure insecure PRNGs".
    PRNGs she advocates are insecure until proven otherwise by crypto
    analysts.

    Anyway, even if I am skeptical about her criticism of popular PRNGs, intuitively I agree with the constructive part of the article - medium-quality PRNG that feeds medium quality hash function can
    potentially produce very good fast PRNG with rather small internal
    state.

    After looking at one of the example PCG generators, I would
    describe it as a medium-quality PRNG that feeds a low-quality
    hash. The particular combination I looked at produced good
    results, but it isn't clear which combinations of PRNG and
    hash would do likewise.


    I tend to like CRC32C for hashing 64 bits into 32 bits; for no reason
    apart from that this primitive is available and fast on modern Intel
    and AMD CPUs. ARM64 CPUs as well, I think, although less than 100% sure.

    On related note, I think that even simple counter fed into high
    quality hash function (not cryptographically high quality, far
    less than that) can produce excellent PRNG with even smaller
    internal state. But not very fast one. Although the speed
    depends on specifics of used computer. I can imagine computer
    that has low-latency Rijndael128 instruction. On such computer,
    running counter through 3-4 rounds of Rijndael ill produce very
    good PRNG that is only 2-3 times slower than, for example, LCG
    128/64.

    I think the point of her paper where she talks about determining
    how much internal state is needed is to measure the efficacy of
    the PRNG, not to try to reduce the amount of state needed. Based
    on my own experience with various PRNGs I think it's a mistake to
    try to minimize the amount of internal state needed. My own rule
    of thumb is to allow at least a factor of four: for example, a
    PRNG with a 32-bit output should have at least 128 bits of state.
    My latest favorite has 256 bits of state to produce 32-bit
    outputs (and so might also do well to produce 64-bit outputs, but
    I haven't tested that).

    One important point that I seem to figure out recently is that the only practical way to produce both solid and very fast PRNG that adheres to
    standard language APIs with 32-bit and to somewhat smaller extent 64-bit output, is to use buffering. I.e. most of the time generator simply
    reads pre-calculated word from the buffer and only ones per N
    iterations runs an actual PRNG algorithm, probably in a loop, often
    in SIMD. In order for this approach to be effective, buffer can't be particularly small. 32 bytes (256 bits) appear to be an absolute
    minimum. The buffer and counter that manages buffering, are parts of the generator state. That alone sets a practical minimal limit on the size
    of generator and diminishes significance of the difference between
    PRNGs with "algorithmic" state of 64 bits, 128 bits or even 256 bits.

    The observation certainly applies to PCGs or to anything else that
    utilizes LCG for its state update primitive.

    Now, if one does no look for ultimate speed then said above does not
    apply.



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Thursday, January 08, 2026 02:57:08
    On Mon, 22 Dec 2025 08:48:10 -0000 (UTC), Michael Sanders wrote:

    [...]

    This puppy is done (at least I'm happy with it).

    Main thing I wanted to accomplish was solid keyboard
    handling in the REPL (so I can apply the knowledge
    gained to another project & I believe I'm pretty close.)

    As it stands the game now has:

    - 3 games in a single binary (mastermind, moo, bagels)

    - man page

    - make file

    - sparse comments...

    Zipped sources [8.3KB] for a few days below:

    <https://drive.google.com/file/d/1PAzCj-Mfx06y2oHz9LQTxa74Aerd2pYe/view?usp=sharing>

    Thanks for the help everyone, I'm gone fishin' for awhile =)

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Thursday, January 08, 2026 15:34:04
    On Wed, 07 Jan 2026 13:54:21 -0800, Keith Thompson wrote:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    John McCue <jmclnx@gmail.com.invalid> writes:
    Michael Sanders <porkchop@invalid.foo> wrote:
    Is it incorrect to use 0 (zero) to seed srand()?

    int seed = (argc >= 2 && strlen(argv[1]) == 9)
    ? atoi(argv[1])
    : (int)(time(NULL) % 900000000 + 100000000);

    srand(seed);

    I like to just read /dev/urandom when I need a random
    number. Seem easier and more portable across Linux &
    the *BSDs.

    int s;
    read(fd, &s, sizeof(int));

    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    And neither is the non-conforming rand() on OpenBSD.

    The rand(1) man page on OpenBSD 7.8 says:

    Standards insist that this interface return deterministic
    results. Unsafe usage is very common, so OpenBSD changed the
    subsystem to return non-deterministic results by default.

    To satisfy portable code, srand() may be called to initialize
    the subsystem. In OpenBSD the seed variable is ignored,
    and strong random number results will be provided from
    arc4random(3). In other systems, the seed variable primes a
    simplistic deterministic algorithm.

    It does provide an srand_deterministic() function that behaves the way srand() is supposed to.

    So then clang would use:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But I don't know (yet) that gcc does as well under OpenBSD.

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Thursday, January 08, 2026 09:26:18
    antispam@fricas.org (Waldek Hebisch) writes:

    Michael S <already5chosen@yahoo.com> wrote:
    [...]
    Anyway, even if I am skeptical about her criticism of popular PRNGs,
    intuitively I agree with the constructive part of the article -
    medium-quality PRNG that feeds medium quality hash function can
    potentially produce very good fast PRNG with rather small internal
    state.

    She seem to care very much about having minimal possible state.
    That is may be nice on embeded systems, but in general I would
    happily accept slighty bigger state (say 256 bits). But if
    we can get good properties with very small state, then why not?
    [...]

    That depends on whether one thinks the tests done to measure
    quality are sufficient to determine all the axes of "good
    properties". I'm not inclined to think that they do. The
    set of tests done in the TestU01 suite are quite good IMO,
    but I don't think they measure all the properties of interest.
    I prefer to err on the side of caution.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Thursday, January 08, 2026 14:44:27
    Michael Sanders <porkchop@invalid.foo> writes:
    On Wed, 07 Jan 2026 13:54:21 -0800, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    And neither is the non-conforming rand() on OpenBSD.

    The rand(1) man page on OpenBSD 7.8 says:

    Standards insist that this interface return deterministic
    results. Unsafe usage is very common, so OpenBSD changed the
    subsystem to return non-deterministic results by default.

    To satisfy portable code, srand() may be called to initialize
    the subsystem. In OpenBSD the seed variable is ignored,
    and strong random number results will be provided from
    arc4random(3). In other systems, the seed variable primes a
    simplistic deterministic algorithm.

    It does provide an srand_deterministic() function that behaves the way
    srand() is supposed to.

    So then clang would use:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But I don't know (yet) that gcc does as well under OpenBSD.

    I don't know what you mean when you say that clang "would use"
    that code.

    I'm not aware that either clang or gcc uses random numbers
    internally. I don't know why they would.

    You could certainly write the above code and compile it with either
    gcc or clang (or any other C compiler on OpenBSD). I've confirmed
    that gcc on OpenBSD does predefine the symbol __OpenBSD__. There
    should be no relevant difference between gcc and clang; random
    number generation is implemented in the library, not in the compiler.

    If your point is that a programmer using either gcc or clang could
    use the above code to get the required deterministic behavior
    for rand(), I agree. (Though it shouldn't be necessary; IMHO the
    OpenBSD folks made a very bad decision.)

    Relatedly, the NetBSD implementation of rand() is conforming, but
    of very low quality. The low-order bit alternates between 0 and
    1 on successive rand() calls, the two low-order bits repeat with
    a cycle of 4, and so on. Larry Jones wrote about it here in 2010:

    The even/odd problem was caused at Berkeley by a well meaning
    but clueless individual who increased the range of the generator
    (which originally matched the sample implementation) by returning
    the *entire* internal state rather than just the high-order
    bits of it. BSD was very popular, so that defective generator
    got around a lot, unfortunately.

    And I've just discovered that the OpenBSD rand() returns alternating
    odd and even results after a call to srand_determinstic().

    It's disturbing that this has never been fixed.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Friday, January 09, 2026 06:06:57
    On Thu, 08 Jan 2026 14:44:27 -0800, Keith Thompson wrote:

    Michael Sanders <porkchop@invalid.foo> writes:
    On Wed, 07 Jan 2026 13:54:21 -0800, Keith Thompson wrote:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    And neither is the non-conforming rand() on OpenBSD.

    The rand(1) man page on OpenBSD 7.8 says:

    Standards insist that this interface return deterministic
    results. Unsafe usage is very common, so OpenBSD changed the
    subsystem to return non-deterministic results by default.

    To satisfy portable code, srand() may be called to initialize
    the subsystem. In OpenBSD the seed variable is ignored,
    and strong random number results will be provided from
    arc4random(3). In other systems, the seed variable primes a
    simplistic deterministic algorithm.

    It does provide an srand_deterministic() function that behaves the way
    srand() is supposed to.

    So then clang would use:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But I don't know (yet) that gcc does as well under OpenBSD.

    I don't know what you mean when you say that clang "would use"
    that code.

    I'm not aware that either clang or gcc uses random numbers
    internally. I don't know why they would.

    Well, I meant the macro itself is (I'm guessing) probably defined
    by clang since its the default compiler.

    You could certainly write the above code and compile it with either
    gcc or clang (or any other C compiler on OpenBSD). I've confirmed
    that gcc on OpenBSD does predefine the symbol __OpenBSD__. There
    should be no relevant difference between gcc and clang; random
    number generation is implemented in the library, not in the compiler.

    This is the info I'm, wondering about: both clang & gcc predefine
    the symbol.

    If your point is that a programmer using either gcc or clang could
    use the above code to get the required deterministic behavior
    for rand(), I agree. (Though it shouldn't be necessary; IMHO the
    OpenBSD folks made a very bad decision.)

    Relatedly, the NetBSD implementation of rand() is conforming, but
    of very low quality. The low-order bit alternates between 0 and
    1 on successive rand() calls, the two low-order bits repeat with
    a cycle of 4, and so on. Larry Jones wrote about it here in 2010:

    The even/odd problem was caused at Berkeley by a well meaning
    but clueless individual who increased the range of the generator
    (which originally matched the sample implementation) by returning
    the *entire* internal state rather than just the high-order
    bits of it. BSD was very popular, so that defective generator
    got around a lot, unfortunately.

    And I've just discovered that the OpenBSD rand() returns alternating
    odd and even results after a call to srand_determinstic().

    It's disturbing that this has never been fixed.

    Yikes! Thanks Keith. This is sort of odd for OpenBSD.


    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Thursday, January 08, 2026 22:46:42
    Michael Sanders <porkchop@invalid.foo> writes:
    On Thu, 08 Jan 2026 14:44:27 -0800, Keith Thompson wrote:
    Michael Sanders <porkchop@invalid.foo> writes:
    [...]
    So then clang would use:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But I don't know (yet) that gcc does as well under OpenBSD.

    I don't know what you mean when you say that clang "would use"
    that code.

    I'm not aware that either clang or gcc uses random numbers
    internally. I don't know why they would.

    Well, I meant the macro itself is (I'm guessing) probably defined
    by clang since its the default compiler.

    You mean the macro __OpenBSD__? Yes, that and other similar macros
    are predefined by the compiler, which is configured for each OS.
    gcc on OpenBSD also predefines it. (I don't know whether it's
    predefined by the preprocessor directly or by some header that's
    included implicitly. That doesn't really matter.) Compilers on
    other platforms will not predefine __OpenBSD__.

    But your original statement implied that clang would *use* that
    particular piece of code, which didn't make much sense. Were you
    just asking about how the __OpenBSD__ macro is defined, without
    reference to srand?

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Friday, January 09, 2026 00:36:21
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    John McCue <jmclnx@gmail.com.invalid> writes:

    Michael Sanders <porkchop@invalid.foo> wrote:

    Is it incorrect to use 0 (zero) to seed srand()?

    int seed = (argc >= 2 && strlen(argv[1]) == 9)
    ? atoi(argv[1])
    : (int)(time(NULL) % 900000000 + 100000000);

    srand(seed);

    I like to just read /dev/urandom when I need a random
    number. Seem easier and more portable across Linux &
    the *BSDs.

    int s;
    read(fd, &s, sizeof(int));

    Apples and oranges. Many applications that use random numbers
    need a stream of numbers that is deterministic and reproducible,
    which /dev/urandom is not.

    And neither is the non-conforming rand() on OpenBSD.

    The rand(1) man page on OpenBSD 7.8 says:

    Standards insist that this interface return deterministic
    results. Unsafe usage is very common, so OpenBSD changed the
    subsystem to return non-deterministic results by default.

    To satisfy portable code, srand() may be called to initialize
    the subsystem. In OpenBSD the seed variable is ignored,
    and strong random number results will be provided from
    arc4random(3). In other systems, the seed variable primes a
    simplistic deterministic algorithm.

    Apparently the OpenBSD folks have seen fit to remove the only
    desirable property that ISO C actually specifies for the standard
    library random number generator. Bravo!

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael Sanders@3:633/10 to All on Friday, January 09, 2026 22:38:59
    On Thu, 08 Jan 2026 22:46:42 -0800, Keith Thompson wrote:

    But your original statement implied that clang would *use* that
    particular piece of code, which didn't make much sense. Were you
    just asking about how the __OpenBSD__ macro is defined, without
    reference to srand?

    Well, under OpenBSD I plan on using:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But what I was asking is whether or not gcc would recognize
    the __OpenBSD__ macro (why wouldn't I'm assuming) since clang
    is the default compiler.

    But also about srand()... you've got me really wondering why
    OpenBSD would deviate from the standard as they have. I get
    that the those folks disagree because its deterministic, but
    its the accepted standard to be deterministic with srand().

    Only speaking for myself here, rather than srand_deterministic()
    and srand() (that's not deterministic under OpenBSD) it
    would've made more sense to've implemented srand_non_deterministic()
    and left srand() alone. That design decision on their part only
    muddies the waters in my thinking. Live & learn =)

    --
    :wq
    Mike Sanders

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Friday, January 09, 2026 23:27:15
    Michael Sanders <porkchop@invalid.foo> writes:
    On Thu, 08 Jan 2026 22:46:42 -0800, Keith Thompson wrote:

    But your original statement implied that clang would *use* that
    particular piece of code, which didn't make much sense. Were you
    just asking about how the __OpenBSD__ macro is defined, without
    reference to srand?

    Well, under OpenBSD I plan on using:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But what I was asking is whether or not gcc would recognize
    the __OpenBSD__ macro (why wouldn't I'm assuming) since clang
    is the default compiler.

    $ gcc -dM -E - < /dev/null

    will show all the preprocessor macros predefined by the compiler.

    There 397 predefined macros on my Fedora gcc 14 installation.

    Note that other macros may be defined in header files.



    But also about srand()... you've got me really wondering why
    OpenBSD would deviate from the standard as they have. I get
    that the those folks disagree because its deterministic, but
    its the accepted standard to be deterministic with srand().

    I expect they were primary concerned with the security
    implications of a deterministic algorithm.


    Only speaking for myself here, rather than srand_deterministic()
    and srand() (that's not deterministic under OpenBSD) it
    would've made more sense to've implemented srand_non_deterministic()
    and left srand() alone. That design decision on their part only
    muddies the waters in my thinking. Live & learn =)

    I'm sure they wanted the change to apply by default to existing
    applications (many of them likely distributed with various BSD
    releases).


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Friday, January 09, 2026 17:09:47
    Michael Sanders <porkchop@invalid.foo> writes:
    On Thu, 08 Jan 2026 22:46:42 -0800, Keith Thompson wrote:
    But your original statement implied that clang would *use* that
    particular piece of code, which didn't make much sense. Were you
    just asking about how the __OpenBSD__ macro is defined, without
    reference to srand?

    Well, under OpenBSD I plan on using:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    But what I was asking is whether or not gcc would recognize
    the __OpenBSD__ macro (why wouldn't I'm assuming) since clang
    is the default compiler.

    OK.

    Do you understand that your original question was unclear?

    You said that "clang would use" the quoted 5-line code snippet,
    and asked whether "gcc does as well". It's not clang or gcc that
    would use that code. It would be used by a programmer writing code
    to be compiled with clang or gcc.

    I understand now what you meant. I'd like to be sure that you
    understand the problem with the question as you originally wrote it.

    I have clang 19.1.7 and gcc 13.2.0 installed on OpenBSD 7.8, and
    both predefine the macro __OpenBSD__.

    But also about srand()... you've got me really wondering why
    OpenBSD would deviate from the standard as they have. I get
    that the those folks disagree because its deterministic, but
    its the accepted standard to be deterministic with srand().

    Only speaking for myself here, rather than srand_deterministic()
    and srand() (that's not deterministic under OpenBSD) it
    would've made more sense to've implemented srand_non_deterministic()
    and left srand() alone. That design decision on their part only
    muddies the waters in my thinking. Live & learn =)

    I don't know why they made that decision. It was clearly deliberate.
    I agree that adding an srand_non_deterministic() function would
    have been better.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Kaz Kylheku@3:633/10 to All on Saturday, January 10, 2026 19:44:01
    On 2026-01-09, Michael Sanders <porkchop@invalid.foo> wrote:
    On Thu, 08 Jan 2026 22:46:42 -0800, Keith Thompson wrote:

    But your original statement implied that clang would *use* that
    particular piece of code, which didn't make much sense. Were you
    just asking about how the __OpenBSD__ macro is defined, without
    reference to srand?

    Well, under OpenBSD I plan on using:

    #ifdef __OpenBSD__
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    This is is better

    // In some common configuration header:

    #ifdef __OpenBSD__
    #define HAVE_SRAND_DETERMINISTIC 1
    #define HAVE_... /* other such macros */
    #endif

    (Or the configuration can be generated by scripts which detect features
    in environment.)

    Then in the code:

    #if HAVE_SRAND_DETERMINISTIC
    srand_deterministic(seed);
    #else
    srand(seed);
    #endif

    If a platform other than __OpenBSD__ comes along which has
    srand_deterministic you just make sure HAVE_SRAND_DETERMINISTIC 1 is
    turned on; you don't have to edit the code where that is used.

    This idea is seen in the configuration of GNU programs and such.

    There is a "GDB Internals" document which discusses it in a section
    called "Clean Design"

    Partial quote:

    New #ifdef?s which test for specific compilers or manufacturers or
    operating systems are unacceptable. All #ifdef?s should test for
    features. The information about which configurations contain which
    features should be segregated into the configuration files. Experience
    has proven far too often that a feature unique to one particular system
    often creeps into other systems; and that a conditional based on some
    predefined macro for your current system will become worthless over
    time, as new versions of your system come out that behave differently
    with regard to this feature.

    [ ... more discussion ... ]

    https://www.sourceware.org/gdb/5/onlinedocs/gdbint.pdf

    I think the GNU Coding Standards document may have had a similar
    discussion; I don't see it in the current version though.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)