Wuthering Heights Review

Feb. 20th, 2026 11:59 pm
pandarus: (Default)
[personal profile] pandarus
Just come back from watching “Wuthering Heights”. I’m not mad about it, in either sense. Here be incoherent thoughts:

- it’s a 2 hour long music video: glib, flamboyant & silly.

- the child actors were GREAT. Bless them. Cracking work, really sad that the story scooted forward to the adult actors so fast.

- I love Margot Robbie & I mean no disrespect when I say Read more... )

me and my big mouth

Feb. 20th, 2026 05:07 pm
watersword: Bare trees in a white landscape (Stock: winter)
[personal profile] watersword

Uh, so, I have a weird Jew-y dilemna.

I volunteer with my neighborhood "snow brigade", which shovels for folks who need help. We're due to get some gross "wintry mix" and "icy sleet" overnight, although maybe not much accumulation.

The couple I got assigned to emailed to say — well, here: "Hopefully there will be NO snow on Friday night and Saturday since for religious reasons we are not able to shovel. If it's not much we can deal with it Saturday night."

I emailed back to say that I don't consider helping a neighbor in need to violate shomer Shabbat and I would be happy to come by and make sure their sidewalks and steps are clear.

They said, "It would be our sin to have another Jew do any work for us on Shabbos. We very much appreciate your kind thoughts to help us. But if we can't do it, you can't do it for us either."

Uhhhhhhhhhh. I am not sure how to respond to this. I don't think this is a sin! I try to observe Shabbat in the sense of resting and renewing myself, but very much not in a traditional way — like, spending a couple of hours mending and embroidering might be part of Shabbat for me because it fills my cup and I don't always get the chance to during the week! Going to the farmer's market and spending half my paycheck and cooking something elaborate on Saturday is a profoundly Shabbosdik thing for me! I don't want to tell them "your theology is wrong" and I don't want to upset them by doing something they have told me not to do (and would apparently feel guilty about????), but ... I can't just leave an elderly couple trapped in their house with icy sidewalks for a day!

*pinches bridge of nose*

I gotta get in touch with the snow brigade coordinator and tell her what's going on so she can try to find a substitute, I guess. I wish I hadn't made it so obvious I am also Jewish, just said something cheerful about being happy to shovel in the morning, but it truly did not occur to me that their observance would mean this. My bad. Ugh.

This is gonna be a real fun conversation with the snow brigade coordinator.

ETA: Snow brigade coordinator is going to check if there's someone I can swap with for future Saturdays, but since the blizzard has been delayed until Monday, when labor is allowed, we will deal with it if and when it becomes a problem next. What a ridiculous shenanigan.

Error'd: Three Blinded Mice

Feb. 20th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Lyle Seaman

...sent us five wtfs. And so on anon.

Item the first, an anon is "definitely not qualified" for this job. "These years of experience requirements are getting ridiculous."

0

 

Item the second unearthed by a farmanon has a loco logo. "After reading about the high quality spam emails which are indistinguishable from the company's emails, I got one from the spammer just starting his first day."

1

 

In thrid place, anon has only good things to say: "I'm liking their newsletter recommendations so far."

2

 

"A choice so noice, they gave it twoice," quipped somebody.

3

 

And foinally, a tdwtfer asks "I've seen this mixmastered calendering on several web sites. Is there an OSS package that is doing this? Or is it a Wordpress plugin?" I have a sneaking suspicion I posted this before. Call me on it.

4

 

Image [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

(no subject)

Feb. 19th, 2026 09:31 pm
watersword: Graffiti scrawl of "ignore this text" (Stock: ignore this text)
[personal profile] watersword

I seem to be Canadian now, which is very exciting. (My paternal grandfather was born in Ontario.) I need to pull together a relatively short stack of documents to prove it (3 birth certificates, 2 marriage certificates, 2 name change records), and fingers crossed Canada (home and native laaaaaand) will welcome me home.

It is supposed to snow AGAIN this weekend. I keep reminding myself that this is how winter is supposed to be.

My to-do list has three MUST DOs on it:

  • write up notes for therapist before Monday session
  • read & comment on manuscript for crit group Tuesday
  • pollinator garden email

If you see me doing anything else except, like, keeping body and soul together for the next few days (if it snows more than half an inch, I'll have to take care of my neighbors, and a friend is coming over with her kid to encourage me to clean and have dinner, but other than that — !), yell at me until I go back to my aforementioned tasks.

I spent this week in slide deck hell and the week before in spreadsheet hell. There is still more slide deck hell to come, but I think I can pace it out a little more now. But spreadsheet hell will not end until May, thanks to HHS (pdf link). I like accessibility work, but I also like digital paleography and information architecture and wireframing and right now accessibility is expanding to fill all the available time and then some. Fortunately, one of the slide decks from hell actually requires me to work on a writing project, so I can cling to some vestige of being a creative person who doesn't live in slide deck or speadsheet hell. Maybe someday I will actually be one! Maybe someday I can contribute to CanLit!

CodeSOD: Terned Backwards

Feb. 19th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

Antonio has an acquaintance has been seeking career advancement by proactively hunting down and fixing bugs. For example, in one project they were working on, there was a bug where it would incorrectly use MiB for storage sizes instead of MB, and vice-versa.

We can set aside conspiracy theories about HDD and RAM manufacturers lying to us about sizes by using MiB in marketing. It isn't relevant, and besides, its not like anyone can afford RAM anymore, with crazy datacenter buildouts. Regardless, which size to use, the base 1024 or base 1000, was configurable by the user, so obviously there was a bug handling that flag. Said acquaintance dug through, and found this:

const baseValue = useSI ? 1000 : 1024;

I know I have a "reputation" when it comes to hating ternaries, but this is a perfectly fine block of code. It is also correct: if you're using SI notation, you should do base 1000.

Now, given that this code is correct, you or I might say, "Well, I guess that isn't the bug, it must be somewhere else." Not this intrepid developer, who decided that they could fix it.

//            const baseValue = useSI ? 1000 : 1024;
            baseValue = 1024
            if (useSI === false)
            {
                baseValue = 1000;
            }
            if (useSI === true)
            {
                baseValue = 1024;
            }

It's rather amazing to see a single, correct line, replaced with ten incorrect lines, and I'm counting commenting out the correct line as one of them.

First, this doesn't correctly declare baseValue, which JavaScript is pretty forgiving about, but it also discards constness. Of course, you have to discard constness now that you've gotten rid of the ternary.

Then, our if statement compares a boolean value against a boolean literal, instead of simply if(!useSI). We don't use an else, despite an else being absolutely correct. Or actually, since we defaulted baseValue, we don't even need an else!

But of course, all of that is just glitter on a child's hand-made holiday card. The glue holding it all together is that this code just flips the logic. If we're not using SI, we set baseValue to 1000, and if we are using SI, we set it to 1024. This is wrong. This is the opposite of what the code says we should do, what words mean, and how units work.

Image [Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

CodeSOD: Contains Some Bad Choices

Feb. 18th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

While I'm not hugely fond of ORMs (I'd argue that relations and objects don't map neatly to each other, and any ORM is going to be a very leaky abstraction for all but trivial cases), that's not because I love writing SQL. I'm a big fan of query-builder tools; describe your query programatically, and have an API that generates the required SQL as a result. This cuts down on developer error, and also hopefully handles all the weird little dialects that every database has.

For example, did you know Postgres has an @> operator? It's a contains operation, which returns true if an array, range, or JSON dictionary contains your search term. Basically, an advanced "in" operation.

Gretchen's team is using the Knex library, which doesn't have a built-in method for constructing those kinds of queries. But that's fine, because it does offer a whereRaw method, which allows you to supply raw SQL. The nice thing about this is that you can still parameterize your query, and Knex will handle all the fun things, like transforming an array into a string.

Or you could just not use that, and write the code yourself:

exports.buildArrayString = jsArray => {
  // postgres has some different array syntax
  // [1,2] => '{1,2}'
  let arrayString = '{';
  for(let i = 0; i < jsArray.length; i++) {
    arrayString += jsArray[i];
    if(i + 1 < jsArray.length) {
      arrayString += ','
    }
  }
  arrayString += '}';
  return arrayString;
}

There's the string munging we know and love. This constructs a Postgres array, which is wrapped in curly braces.

Also, little pro-tip for generating comma separated code, and this is just a real tiny optimization: before the loop append item zero, start the loop with item 1, and then you can unconditionally prepend a comma, removing any conditional logic from your loop. That's not a WTF, but I've seen so much otherwise good code make that mistake I figured I'd bring it up.

exports.buildArrayContainsQuery = (key, values) => {
  // TODO: do we need to do input safety checks here?
  // console.log("buildArrayContainsQuery");

  // build the postgres 'contains' query to compare arrays
  // ex: to fetch files by the list of tags

  //WORKS:
  //select * from files where _tags @> '{2}';
  //query.whereRaw('_tags @> ?', '{2}')

  let returnQueryParams = [];
  returnQueryParams.push(`${key} @> ?`);
  returnQueryParams.push(exports.buildArrayString(values));
  // console.log(returnQueryParams);
  return returnQueryParams;
}

And here's where it's used. "do we need input safety checks here?" is never a comment I like to see as a TODO. That said, because we are still using Knex's parameter handling, I'd hope it handles escaping correctly so that the answer to this question is "no". If the answer is "yes" for some reason, I'd stop using this library!

That said, all of this code becomes superfluous, especially when you read the comments in this function. I could just directly run query.whereRaw('_tags @> ?', myArray); I don't need to munge the string myself. I don't need to write a function which returns an array of parameters that I have to split back up to pass to the query I want to call.

Here's the worst part of all of this: these functions exist in a file called sqlUtils.js, which is just a pile of badly re-invented wheels, and the only thing they have in common is that they're vaguely related to database operations.

Image [Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

CodeSOD: Waiting for October

Feb. 17th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

Arguably, the worst moment for date times was the shift from Julian to Gregorian calendars. The upgrade took a long time, too, as some countries were using the Julian calendar over 300 years from the official changeover, famously featured in the likely aprochryphal story about Russia arriving late for the Olympics.

At least that change didn't involve adding any extra months, unlike some of the Julian reforms, which involved adding multiple "intercalary months" to get the year back in sync after missing a pile of leap years.

Speaking of adding months, Will J sends us this "calendar" enum:

enum Calendar
{
    April = 0,
    August = 1,
    December = 2,
    February = 3,
    Friday = 4,
    January = 5,
    July = 6,
    June = 7,
    March = 8,
    May = 9,
    Monday = 10,
    November = 11,
    October = 12,
    PublicHoliday = 13,
    Saturday = 14,
    Sunday = 15,
    September = 16,
    Thursday = 17,
    Tuesday = 18,
    Wednesday = 19
}

Honestly, the weather in PublicHoliday is usually a bit too cold for my tastes. A little later into the spring, like Saturday, is usually a nicer month.

Will offers the hypothesis that some clever developer was trying to optimize compile times: obviously, emitting code for one enum has to be more efficient than emitting code for many enums. I think it more likely that someone just wanted to shove all the calendar stuff into one bucket.

Will further adds:

One of my colleagues points out that the only thing wrong with this enum is that September should be before Sunday.

Yes, arguably, since this enum clearly was meant to be sorted in alphabetical order, but that raises the question of: should it really?

Image [Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

Airplane seat cushion help

Feb. 16th, 2026 08:44 pm
amalthia: (MLP Rainbow Dash)
[personal profile] amalthia
I'm searching for airplane seat cushions.

I was hoping someone on my friend's list has tried a few cushions or has a favorite they'd recommend for long haul air travel? Like 12 hours and more air travel?

Living in Alaska long flights are the norm but I think I have to accept I'm growing older and traveling is painful.

I'd appreciate any and all advice! Sadly getting out of the plane and swimming the rest of the way won't work....

CodeSOD: C+=0.25

Feb. 16th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

A good C programmer can write C in any language, especially C++. A bad C programmer can do the same, and a bad C programmer will do all sorts of terrifying things in the process.

Gaetan works with a terrible C programmer.

Let's say, for example, you wanted to see if an index existed in an array, and return its value- or return a sentinel value. What you definitely shouldn't do is this:

    double Module::GetModuleOutput(int numero) {
        double MAX = 1e+255 ;
        if (this->s.sorties+numero )
            return this->s.sorties[numero];
        else
            return MAX ;
    }

sorties is an array. In C, you may frequently do some pointer arithmetic operations, which is why sorties+numero is a valid operation. If we want to be pedantic, *(my_array+my_index) is the same thing as my_array[my_index]. Which, it's worth noting, both of those operations de-reference an array, which means you better hope that you haven't read off the end of the array.

Which is what I suspect their if statement is trying to check against. They're ensuring that this->s.sorties+numero is not a non-zero/false value. Which, if s.sorties is uninitialized and numero is zero, that check will work. Otherwise, that check is useless and does nothing to ensure you haven't read off the end of the array.

Which, Gaetan confirms. This code works "because in practice, GetModuleOutput is called for numero == 0 first. It never de-references off the end of the array, not because of defensive programming, but because it just never comes up in actual execution.

Regardless, if everything is null, we return 1e+255, which is not a meaningful value, and should be treated like a sentinel for "no real value". None of the calling code does that, however, but also, it turns out not to matter.

This pattern is used everywhere there is arrays, except the handful of places where this pattern is not used.

Then there's this one:

    if(nb_type_intervalle<1)    { }
    else 
        if((tab_intervalle=(double*)malloc(nb_lignes_trouvees*nb_type_intervalle*2 \
                                                        *sizeof(double)))==NULL)
            return(ERREUR_MALLOC);

First, I can't say I love the condition here. It's confusing to have an empty if clause. if (nb_type_intervalle>=1) strikes me as more readable.

But readability is boring. If we're in the else clause, we attempt a malloc. While using malloc in C++ isn't automatically wrong, it probably is. C++ has its own allocation methods that are better at handling things like sizes of datatypes. This code allocates memory for a large pile of doubles, and stores a pointer to that memory in tab_intervalle. We do all this inside of an if statement, so we can then check that the resulting pointer is not NULL; if it is, the malloc failed and we return an error code.

The most frustrating thing about this code is that it works. It's not going to blow up in surprising ways. I never love doing the "assignment and check" all in one statement, but I've seen it enough times that I'd have to admit it's idiomatic- to C style programming. But that bit of code golf coupled with the pointlessly inverted condition that puts our main logic in the else just grates against me.

Again, that pattern of the inverted conditional and the assignment and check is used everywhere in the code.

Gaetan leaves us with the following:

Not a world-class WTF. The code works, but is a pain in the ass to inspect and document

In some ways, that's the worst situation to be in: it's not bad enough to require real work to fix it, but it's bad enough to be frustrating at every turn.

Image [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

(no subject)

Feb. 16th, 2026 01:33 pm
watersword: A young white woman raising a feathery Venetian mask to her face (Stock: mask)
[personal profile] watersword

ARGH, the box where I stashed a bunch of pharmacy receipts has vanished into thin air and I cannot imagine where it is, nor can I persuade myself I would have thrown it out! This apartment is not large. I cannot remember the last time I saw it, but this doesn't say much.

I have made progress on the jeans I am repairing, except that there is a new spot that has worn out. It feels positively Sisyphean. Jeans of Theseus. Well, it keeps me from doomscrolling.

Steaming potatoes before browning them continues to be one of the great discoveries of my adulthood: it's so fast! and tidy! and produces perfect potatoes! I do need to acquire bamboo steamers for better steaming of fish and various Asian dishes and whatnot, but first I gotta figure out where would I put them? I have a tiny kitchen and a lot of equipment but I swear I use pretty much all of it (I would use the pasta roller more if eggs were affordable, but that really is the only thing I look at and wince, trying to justify the space). Semi-relatedly, the attempt to make the trash situation less horrible seems to be working: a small trash bin forces me to take it out more often, before the contents get gross. I should've gotten a foot-pedal model, but that is really the only flaw in the system, and I do like that the legs elevate it so I can clean under it easily. It's almost embarrassing how easy this dose of shame was to hack, but better late than never, I guess.

Error'd: Cruel Brittanica

Feb. 13th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Lyle Seaman

"No browser is the best browser," opines Michael R. sarcastically as per usual for tdwtf. "Thank you for suggesting a browser. FWIW: neither latest Chrome, Safari, Firefox, Opera work. Maybe I should undust my Netscape."

3

 

An anonymous dessert lover ruminates "The icing on the cake is that it's for HR where names can be quite important. Just goes to show that not even SAP can do SAP."

5

 

Another anonymous dessert lover (because honestly, who isn't) cheers "2024 is back again."

0

 

Thrice capitalled B.J.H. capitulates. "I guess I'm not cleared to know what topic I subscribed to."

1

 

Jeopardy fan Jeremy P. digs a quick quiz.

It's from Britannica.com. I thought "TV remote control" because it would effectively turn off the TV. The correct answer is toaster.

4

 To understand what went wrong, the previous correct answer was "blunderbuss".

Apparently this is a test for clairvoyance, which will have come in handy.

For a bonus buzz, Jeremy sent in another.


This time it's "guess the novel from the picture". There was a subtle clue in this one.

2

You're a monster, Jeremy. 

Image [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

CodeSOD: Consistently Transactional

Feb. 12th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

It's always good to think through how any given database operation behaves inside of a transaction. For example, Faroguy inherited a Ruby codebase which was mostly db.execute("SOME SQL") without any transactions at all. This caused all sorts of problems with half-finished operations polluting the database.

Imagine Faroguy's excitement upon discovering a function called db_trans getting called in a few places. Well, one place, but that's better than none at all. This clearly must mean that at least one operation was running inside of a transaction, right?

  def self.db_trans(db,stmt)
    db.execute(stmt)
  end # self.db_trans

Oh.

[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.

Copic Marker Layout for Practicality

Feb. 11th, 2026 01:27 pm
bread: vuvuzela (Default)
[personal profile] bread posting in [community profile] dreamwidthlayouts
Title: Copic Marker Layout
Credit to: [community profile] vuvuzela
Base style: Practicality
Type: CSS
Best resolution: Built in 1912x1074 – Mobile responsive
Tested in: Built in Firefox. Tested in Chrome & Opera on Windows OS. Tested in Android OS with Firefox.
Features: Mobile Responsive! Stylized home page, reading page, entry/comments page, icons page, and "more options" reply page.

Image
ImageImage
Click for image previews

( Layout Instructions, Live Preview, & CSS )

CodeSOD: Cover Up

Feb. 11th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

Goodhart's Law states that when a measure becomes a target, it ceases to be a good measure. Or, more to the point: you get what you measure.

If, for example, you measure code coverage, you are going to get code coverage. It doesn't mean the tests will be any good, it just means that you'll write tests that exercise different blocks of code.

For example, Capybara James sends us this unit test:

@MockitoSettings
class CentralizedLoggerTest {
    @InjectMocks
    private CentralizedLogger centralizedLogger;
    @Test
    void logAround() throws Throwable {
        centralizedLogger = new CentralizedLogger();
        MethodSignature signature = mock(MethodSignature.class);
        ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
        when(joinPoint.getSignature()).thenReturn(signature);
        centralizedLogger.logAround(joinPoint);
        Assertions.assertTrue(true);
    }
}

It doesn't really matter what the mocks are, or what gets instantiated, or honestly, anything that's happening here. The assertion is the beginning and ending.

James writes:

The only requirement was sonar coverage to push the code to production. There is no other purpose.

Image [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

(no subject)

Feb. 10th, 2026 09:01 pm
watersword: Keira Knightley, looking at the camera (Keira Knightley: Gaze)
[personal profile] watersword

This might be the first time that Jo Walton's reading list did not result in a half-dozen new library holds, so I unfroze some existing holds and headed over to [personal profile] rivkat's to catch up on her notes on books. Results: several new holds, as expected and intended. I feel much better.

I fought my way past Amtrak's terrible 2FA and did not have to deal with Julie, which definitely counts as dodging the boss battle, but now I am getting errors when I try to buy my Dessa ticket, and in conclusion, computers were a mistake.

The gherkin is asleep on my chest (tiny tiny tiny snores) and allegedly it is going to go above 0° C for the first time in days, possibly weeks, tomorrow.

denise: Image: Me, facing away from camera, on top of the Castel Sant'Angelo in Rome (Default)
[staff profile] denise posting in [site community profile] dw_news
Back in August of 2025, we announced a temporary block on account creation for users under the age of 18 from the state of Tennessee, due to the court in Netchoice's challenge to the law (which we're a part of!) refusing to prevent the law from being enforced while the lawsuit plays out. Today, I am sad to announce that we've had to add South Carolina to that list. When creating an account, you will now be asked if you're a resident of Tennessee or South Carolina. If you are, and your birthdate shows you're under 18, you won't be able to create an account.

We're very sorry to have to do this, and especially on such short notice. The reason for it: on Friday, South Carolina governor Henry McMaster signed the South Carolina Age-Appropriate Design Code Act into law, with an effective date of immediately. The law is so incredibly poorly written it took us several days to even figure out what the hell South Carolina wants us to do and whether or not we're covered by it. We're still not entirely 100% sure about the former, but in regards to the latter, we're pretty sure the fact we use Google Analytics on some site pages (for OS/platform/browser capability analysis) means we will be covered by the law. Thankfully, the law does not mandate a specific form of age verification, unlike many of the other state laws we're fighting, so we're likewise pretty sure that just stopping people under 18 from creating an account will be enough to comply without performing intrusive and privacy-invasive third-party age verification. We think. Maybe. (It's a really, really badly written law. I don't know whether they intended to write it in a way that means officers of the company can potentially be sentenced to jail time for violating it, but that's certainly one possible way to read it.)

Netchoice filed their lawsuit against SC over the law as I was working on making this change and writing this news post -- so recently it's not even showing up in RECAP yet for me to link y'all to! -- but here's the complaint as filed in the lawsuit, Netchoice v Wilson. Please note that I didn't even have to write the declaration yet (although I will be): we are cited in the complaint itself with a link to our August news post as evidence of why these laws burden small websites and create legal uncertainty that causes a chilling effect on speech. \o/

In fact, that's the victory: in December, the judge ruled in favor of Netchoice in Netchoice v Murrill, the lawsuit over Louisiana's age-verification law Act 456, finding (once again) that requiring age verification to access social media is unconstitutional. Judge deGravelles' ruling was not simply a preliminary injunction: this was a final, dispositive ruling stating clearly and unambiguously "Louisiana Revised Statutes §§51:1751–1754 violate the First Amendment of the U.S. Constitution, as incorporated by the Fourteenth Amendment of the U.S. Constitution", as well as awarding Netchoice their costs and attorney's fees for bringing the lawsuit. We didn't provide a declaration in that one, because Act 456, may it rot in hell, had a total registered user threshold we don't meet. That didn't stop Netchoice's lawyers from pointing out that we were forced to block service to Mississippi and restrict registration in Tennessee (pointing, again, to that news post), and Judge deGravelles found our example so compelling that we are cited twice in his ruling, thus marking the first time we've helped to get one of these laws enjoined or overturned just by existing. I think that's a new career high point for me.

I need to find an afternoon to sit down and write an update for [site community profile] dw_advocacy highlighting everything that's going on (and what stage the lawsuits are in), because folks who know there's Some Shenanigans afoot in their state keep asking us whether we're going to have to put any restrictions on their states. I'll repeat my promise to you all: we will fight every state attempt to impose mandatory age verification and deanonymization on our users as hard as we possibly can, and we will keep actions like this to the clear cases where there's no doubt that we have to take action in order to prevent liability.

In cases like SC, where the law takes immediate effect, or like TN and MS, where the district court declines to issue a temporary injunction or the district court issues a temporary injunction and the appellate court overturns it, we may need to take some steps to limit our potential liability: when that happens, we'll tell you what we're doing as fast as we possibly can. (Sometimes it takes a little while for us to figure out the exact implications of a newly passed law or run the risk assessment on a law that the courts declined to enjoin. Netchoice's lawyers are excellent, but they're Netchoice's lawyers, not ours: we have to figure out our obligations ourselves. I am so very thankful that even though we are poor in money, we are very rich in friends, and we have a wide range of people we can go to for help.)

In cases where Netchoice filed the lawsuit before the law's effective date, there's a pending motion for a preliminary injunction, the court hasn't ruled on the motion yet, and we're specifically named in the motion for preliminary injunction as a Netchoice member the law would apply to, we generally evaluate that the risk is low enough we can wait and see what the judge decides. (Right now, for instance, that's Netchoice v Jones, formerly Netchoice v Miyares, mentioned in our December news post: the judge has not yet ruled on the motion for preliminary injunction.) If the judge grants the injunction, we won't need to do anything, because the state will be prevented from enforcing the law. If the judge doesn't grant the injunction, we'll figure out what we need to do then, and we'll let you know as soon as we know.

I know it's frustrating for people to not know what's going to happen! Believe me, it's just as frustrating for us: you would not believe how much of my time is taken up by tracking all of this. I keep trying to find time to update [site community profile] dw_advocacy so people know the status of all the various lawsuits (and what actions we've taken in response), but every time I think I might have a second, something else happens like this SC law and I have to scramble to figure out what we need to do. We will continue to update [site community profile] dw_news whenever we do have to take an action that restricts any of our users, though, as soon as something happens that may make us have to take an action, and we will give you as much warning as we possibly can. It is absolutely ridiculous that we still have to have this fight, but we're going to keep fighting it for as long as we have to and as hard as we need to.

I look forward to the day we can lift the restrictions on Mississippi, Tennessee, and now South Carolina, and I apologize again to our users (and to the people who temporarily aren't able to become our users) from those states.

One Version of Events

Feb. 10th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

Jon supports some software that's been around long enough that the first versions of the software ran on, and I quote, "homegrown OS". They've long since migrated to Linux, and in the process much of their software remained the same. Many of the libraries that make up their application haven't been touched in decades. Because of this, they don't really think too much about how they version libraries; when they deploy they always deploy the file as mylib.so.1.0. Their RPM post-install scriptlet does an ldconfig after each deployment to get the symlinks updated.

For those not deep into Linux library management, a brief translation: shared libraries in Linux are .so files. ldconfig is a library manager, which finds the "correct" versions of the libraries you have installed and creates symbolic links to standard locations, so that applications which depend on those libraries can load them.

In any case, Jon's team's solution worked until it didn't. They deployed a new version of the software, yum reported success, but the associated services refused to start. This was bad, because this happened in production. It didn't happen in test. They couldn't replicate it anywhere else, actually. So they built a new version of one of the impacted libraries, one with debug symbols enabled, and copied that over. They manually updated the symlinks, instead of using ldconfig, and launched the service.

The good news: it worked.

The bad news: it worked, but the only difference was that the library was built with debug symbols. The functionality was exactly the same.

Well, that was the only difference other than the symlink.

Fortunately, a "before" listing of the library files was captured before the debug version was installed, a standard practice by their site-reliability-engineers. They do this any time they try and debug in production, so that they can quickly revert to the previous state. And in this previous version, someone noticed that mylib.so was a symlink pointing to mylib.so.1.0.bkup_20190221.

Once again, creating a backup file is a standard practice for their SREs. Apparently, way back in 2019 someone was doing some debugging. They backed up the original library file, but never deleted the backup. And for some reason, ldconfig had been choosing the backup file when scanning for the "correct" version of libraries. Why?

Here, Jon does a lot of research for us. It turns out, if you start with the man pages, you don't get a answer- but you do get a warning:

ldconfig will look only at files that are named lib*.so* (for regular shared objects) or ld-.so (for the dynamic loader itself). Other files will be ignored. Also, ldconfig expects a certain pat‐
tern to how the symbolic links are set up, like this example, where the middle file (libfoo.so.1 here) is the SONAME for the library:

libfoo.so -> libfoo.so.1 -> libfoo.so.1.12

Failure to follow this pattern may result in compatibility issues after an upgrade.

Well, they followed the pattern, and they found compatibility issues. But what exactly is going on here? Jon did the work of digging straight into the ldconfig source to find out the root cause.

The version detecting algorithm starts by looking directly at filenames. While the man page warns about a convention, ldconfig doesn't validate names against this convention (which is probably the correct decision). Insetad, to find which filename has the highest version number, it scans through two filenames until finds numeric values in both of them, then does some pretty manual numeric parsing:

int _dl_cache_libcmp(const char *p1, const char *p2) {
  while (*p1 != '\0') {
    if (*p1 >= '0' && *p1 <= '9') {
      if (*p2 >= '0' && *p2 <= '9') {
        /* Must compare this numerically.  */
        int val1;
        int val2;

        val1 = *p1++ - '0';
        val2 = *p2++ - '0';
        while (*p1 >= '0' && *p1 <= '9')
          val1 = val1 * 10 + *p1++ - '0';
        while (*p2 >= '0' && *p2 <= '9')
          val2 = val2 * 10 + *p2++ - '0';
        if (val1 != val2)
          return val1 - val2;
      } else
        return 1;
    } else if (*p2 >= '0' && *p2 <= '9')
      return -1;
    else if (*p1 != *p2)
      return *p1 - *p2;
    else {
      ++p1;
      ++p2;
    }
  }
  return *p1 - *p2;
}

NB: this is the version of ldconfig at the time Jon submitted this, and the version that they're using. I haven't dug through to check if this is still true in the latest version. That's an exercise for the reader.

While we have not hit the end of the first string, check if the character in that string is numeric. If it is, check if the character in the second string is numeric. If it is, keep scanning through characters, and for as long as they're numeric, keep parsing them into numbers. If the numbers aren't the same, we return the difference between them.

If the first string contains numbers at this point, but the second string doesn't, return 1. If the second string contains numbers but not the first, return -1. Otherwise, increment our pointers and go to the next character. If we reach the end of the string without finding numeric characters, return the difference between these two characters.

Also, correct me if I'm wrong, but it seems like a malicious set of filenames could cause buffer overruns here.

Now, I'll be honest, I don't have the fortitude to suggest that ldconfig is TRWTF here. It's a venerable piece of software that's solving an extremely hard problem. But boy, DLL Hell is an unending struggle and this particular solution certainly isn't helping. I'm honestly not entirely certain I'd say that there was a true WTF here, just an unfortunate confluence of people doing their best and ending up laying landmines for others.

But here's the fun conclusion: the 2019 version of the library actually had been updated. They'd deployed several new versions between 2019 and 2024, when things finally blew up. The actual deployed software kept using the backup file from 2019, and while it may have caused hard-to-notice and harder-to-diagnose bugs, it didn't cause any crashes until 2024.

Image [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

good things

Feb. 9th, 2026 02:49 pm
watersword: Keira Knightley applying lipstick and looking in a mirror, with the words "a work in progress" nearby (Keira Knightley: lipstick)
[personal profile] watersword
  1. I have wonderful friends who validate me when I'm having a hard time.
  2. Farmer's market pesto in the freezer in the middle of winter.
  3. My team won a prestigious award at work and I got to read the nomination and it says really lovely things about the work we do.
  4. I already had the book Humankind: a hopeful history out from the library and after encountering Too Many Informations about the Epstein files, I started reading it and it is exactly what I need right now (although I would very much like to know what e.g. Maimonides' thoughts are on Bregman's argument, as well as wisdom traditions from India and China; maybe we'll get there).
  5. The public library is giving out free seeds which means it WILL be spring someday.

CodeSOD: Invalid Passport

Feb. 9th, 2026 06:30 am
[syndicated profile] the_daily_wtf_feed

Posted by Remy Porter

Gretchen wanted to, in development, disable password authentication. Just for a minute, while she was testing things. That's when she found this approach to handling authentication.

passport.authenticate('local', { session: true }, async (err, user) => {
  if (err) {
    res.send({ success: false, message: 'Error authenticating user.' })
  } else if (!user) {
    User.query()
      .where({ username: req.body.username })
      .first()
      .then(targetUser => {
        if (targetUser) {
          const hash = User.hashPassword(
            targetUser.password_salt,
            req.body.password
          )
          if (hash === targetUser.password_hash) {
            res.send({
              success: false,
              message: 'Incorrect username or password.',
            })
          } else {
            res.send({
              success: false,
              message: 'Incorrect username or password.',
            })
          }
        } else {
          res.send({
            success: false,
            message: 'Incorrect username or password.',
          })
        }
      })
      .catch(err => {
        res.send({ success: false, message: 'Internal server error' })
      })
  } else if (user.firstLogin) {
//......
  }
})(req, res, next);

passport.authenticate invokes its callback after attempting to authenticate. Now, normally, this is called as middleware on a route defined on the webserver- that is to say, you don't call it from within your application code, but as part of your routing configuration. That's not the case here, where this blob is inside of a controller.

That's weird, but let's just trace through this code. We attempt to authenticate. When the process completes, our callback function executes. If authentication failed, there's an error, so we'll send an error message. Then, if the user object isn't populated, we attempt to look up the user. If we find a user with that user name, we then hash their password and check if the hash matches. If it does, we send an error message. If it doesn't, we send an error message. If we didn't find the user, we send an error message. If anything goes wrong, we send an error message.

Wait a second, back up: if the user exists and their password matches, we send an error message?

I'll let Gretchen explain a bit more:

passport.authenticate returns an error if the authentication failed and a user object, if it succeeded. We check this immediately: if error is set, return an error message. But then, we check if the user does not exist (aka: the authentication failed).

Yes, the reason user would be null is because the authentication failed. So the error would be set. So that entire branch about validating the user won't happen: either the authentication worked and we know who the user is, or it failed, in which case we'd have an error. There's no reasonable world where there's no error but also no user object.

So yes, if authentication failed, but you manually re-run the authentication and it succeeds for some reason, yeah, you probably should still return an error. But I don't know if it's "Incorrect username or password". It probably should be "Invalid reality, please restart the universe and see if the problem persists."

[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!

no. no, thank you.

Feb. 8th, 2026 09:50 pm
watersword: A smiling woman giving thumbs-up and the words "I've made a huge mistake" (The Good Place: huge mistake)
[personal profile] watersword

Another 4 inches of snow? And high winds? And "arctic chill"? I cannot.

I am trying the applesauce loaf again, this time with some chunks of "Gold Rush" apples in the batter and making sure not to use lumpy brown sugar. Fingers crossed.

Amtrak's 2FA system is garbage and I may have to contend with Julie, my nemesis (Amtrak's phone customer "service" bot) to get to New York to see Dessa in March (and sneak out of a conference early); my splurge on Restaurant Week was kind of a waste of money (pasta oversalted, rosé weirdly bland); I am sick of all my clothes, no doubt because I have been wearing all of them at the same time for the past month, and the idea of acquiring different clothes is the epitome of exchanging money for bads and disservices.

THIS IS THE BAD PLACE.

Profile

cal: (Default)
cal

November 2009

S M T W T F S
1234567
8910111213 14
15161718192021
22232425262728
2930     

Style Credit

Expand Cut Tags

No cut tags