HN user

dbremner

14 karma

https://github.com/dbremner

Posts2
Comments17
View on HN

I'm rewriting a suite of network applications from C++ to Rust as a learning exercise. It's a long obsolete and obscure protocol, so the results aren't particularly useful, but it's been a good introduction to the language.

This is a 30+ year-old codebase that originally started as pre-ANSI C. The design tradeoffs were very different at the time. I've managed to compile it as C++23 with unreasonably high warning levels, and it's now warning-free. However, there are still many unresolved issues.

One notable limitation is the use of a SIGINT handler implemented with setjmp/longjmp, which reduces the effectiveness of RAII.

Regarding textToStr, there were four instances where it was called twice in the same expression. To avoid potential problems, I replaced these calls with a temporary std::string to store the result of the first call before the second is made. In hindsight, none of these cases likely would have caused issues, but I preferred not to take risks. The SigIntGuard ensures that the std::string destructor runs even if a SIGINT occurs:

    {
        SigIntGuard guard;
        std::string const member{textToView(textOf(fst(b)))};
        std::print(errorStream, R"(No member "{}" in class "{}")", member, textToView(klass(c).text));
    }

Here is a real safety issue that I found and fixed a couple weeks ago. This is an ancient language runtime which originally ran on MS-DOS, Amiga, Atari, and at least a dozen now-discontinued commercial Unices. I've been porting it to 64-bit OSes as a weekend hack. While this particular issue is unlikely to appear in modern applications, a similar pattern might manifest today as a use-after-free error with std::string_view or an invalid iterator.

Background:

    typedef int Text; 
The Text type is used to encode different kinds of string-like values. Negative values represent a generated dictionary. Valid indexes in the string intern table (https://en.wikipedia.org/wiki/String_interning) represent a stored string. Other values represent generated variable names.

const char *textToStr(Text t) - This takes a Text value and returns a pointer to a null-terminated string. If t is a string intern index, then it returns a pointer to the stored string. If t represents either a generated dictionary or generated variable name, then it calls snprintf on a static buffer and returns the buffer's address.

Problem:

The use of a static buffer in textToStr introduces a temporal safety issue when multiple calls are made in the same statement. Here’s an excerpt from a diagnostic error message, simplified for clarity:

    printf(stderr, "Invalid use of \"%s\" with \"%s\"",
                textToStr(e),
                textToStr(s));
If both e and s are generated dictionaries or variables, then each call to textToStr overwrites the static buffer used by the other. Since the evaluation order of function arguments in C++ is undefined, the result is unpredictable and depends on the compiler and runtime.

I'm not sure about static analyzers, but here are the clang warnings I use for my personal C++20 projects. You will get an enormous number of warnings from typical C++ code. I fix all of them, but doubt it would make sense to do so in a commercial environment.

-Weverything - this enables every clang warning

-Wno-c++98-compat - warns about using newer C++ features

-Wno-c++98-compat-pedantic - warns about using newer C++ features

-Wno-padded - warns about alignment padding. I optimize struct layout, so this warning only reports on cases I couldn't resolve.

-Wno-poison-system-directories - I'm not cross-compiling anything.

-Wno-pre-c++20-compat-pedantic - warns about using newer C++ features

ReSharper (and presumably IntelliJ) supports expression-based search and replace.

Here are some commits where I used it to remove boilerplate from some test cases. The code was written long before MSTest added support for Assert.ThrowsException.

https://github.com/dbremner/PowerCollections/commit/a364a154...

https://github.com/dbremner/PowerCollections/commit/1de2f916...

https://github.com/dbremner/PowerCollections/commit/183e3c7c...