PSA: stop using mozilla::PodZero and mozilla::PodArrayZero

I’ve blogged about surprising bits of the C++ object model before, and I’m back with more.

Executive summary: Don’t use mozilla::PodZero or mozilla::PodArrayZero. Modern C++ provides better alternatives that don’t presume that writing all zeroes will always correctly initialize the given type. Use constructors, in-class member initializers, and functions like std::fill to zero member fields.

The briefest recap of salient parts of the C++ object model

C++ as a language really wants to know when objects are created so that compilers can know that this memory contains an object of this type. Compilers then can assume that writing an object of one type, won’t conflict with reads/writes of incompatible types.

double foo(double* d, int* i, int z)
  *d = 3.14;

  // int/double are incompatible, so this write may be
  // assumed not to change the value of *d.
  *i = z;

  // Therefore *d may be assumed to still be 3.14, so this
  // may be compiled as 3.14 * z without rereading *d.
  return *d * z;

You can’t use arbitrary memory as your desired type after a cast. An object of that type must have been explicitly created there: e.g. a local variable of that type must be declared there, a field of that type must be defined and the containing object created, the object must be created via new, &c.

Misinterpreting an object using an incompatible type violates the strict aliasing rules in [basic.lval]p11.

memsetting an object

memset lets you write characters over memory. C code routinely used this to fill an array or struct with zeroes or null pointers or similar, assuming all-zeroes writes the right value.

C++ code also sometimes uses memset to zero out an object, either after allocating its memory or in the constructor. This doesn’t create a T (you’d need to placement-new), but it often still “works”. But what if T changes to require initialization? Maybe a field in T gains a constructor (T might never be touched!) or a nonzero initializer, making T a non-trivial type. memset could hide that fresh initialization requirement or (depending when the memset happens) overwrite a necessary initialization.

Problem intensifies

Unfortunately, Mozilla code has provided and promoted a PodZero function that misuses memset this way. So when I built with gcc 8.0 recently (I usually use a home-built clang), I discovered a torrent of build warnings about memset misuse on non-trivial types. A taste:

In file included from /home/jwalden/moz/after/js/src/jit/BitSet.h:12,
                 from /home/jwalden/moz/after/js/src/jit/Safepoints.h:10,
                 from /home/jwalden/moz/after/js/src/jit/JitFrames.h:13,
                 from /home/jwalden/moz/after/js/src/jit/BaselineFrame.h:10,
                 from /home/jwalden/moz/after/js/src/vm/Stack-inl.h:15,
                 from /home/jwalden/moz/after/js/src/vm/Debugger-inl.h:12,
                 from /home/jwalden/moz/after/js/src/vm/DebuggerMemory.cpp:29,
                 from /home/jwalden/moz/after/js/src/dbg/js/src/Unified_cpp_js_src32.cpp:2:
/home/jwalden/moz/after/js/src/jit/JitAllocPolicy.h: In instantiation of ‘T* js::jit::JitAllocPolicy::maybe_pod_calloc(size_t) [with T = js::detail::HashTableEntry<js::HashMapEntry<JS::Value, unsigned int> >; size_t = long unsigned int]’:
/home/jwalden/moz/after/js/src/dbg/dist/include/js/HashTable.h:1293:63:   required from ‘static js::detail::HashTable<T, HashPolicy, AllocPolicy>::Entry* js::detail::HashTable<T, HashPolicy, AllocPolicy>::createTable(AllocPolicy&, uint32_t, js::detail::HashTable<T, HashPolicy, AllocPolicy>::FailureBehavior) [with T = js::HashMapEntry<JS::Value, unsigned int>; HashPolicy = js::HashMap<JS::Value, unsigned int, js::jit::LIRGraph::ValueHasher, js::jit::JitAllocPolicy>::MapHashPolicy; AllocPolicy = js::jit::JitAllocPolicy; js::detail::HashTable<T, HashPolicy, AllocPolicy>::Entry = js::detail::HashTableEntry<js::HashMapEntry<JS::Value, unsigned int> >; uint32_t = unsigned int]’
/home/jwalden/moz/after/js/src/dbg/dist/include/js/HashTable.h:1361:28:   required from ‘bool js::detail::HashTable<T, HashPolicy, AllocPolicy>::init(uint32_t) [with T = js::HashMapEntry<JS::Value, unsigned int>; HashPolicy = js::HashMap<JS::Value, unsigned int, js::jit::LIRGraph::ValueHasher, js::jit::JitAllocPolicy>::MapHashPolicy; AllocPolicy = js::jit::JitAllocPolicy; uint32_t = unsigned int]’
/home/jwalden/moz/after/js/src/dbg/dist/include/js/HashTable.h:92:69:   required from ‘bool js::HashMap<Key, Value, HashPolicy, AllocPolicy>::init(uint32_t) [with Key = JS::Value; Value = unsigned int; HashPolicy = js::jit::LIRGraph::ValueHasher; AllocPolicy = js::jit::JitAllocPolicy; uint32_t = unsigned int]’
/home/jwalden/moz/after/js/src/jit/LIR.h:1901:38:   required from here
/home/jwalden/moz/after/js/src/jit/JitAllocPolicy.h:101:19: warning: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘class js::detail::HashTableEntry<js::HashMapEntry<JS::Value, unsigned int> >’ with no trivial copy-assignment [-Wclass-memaccess]
             memset(p, 0, numElems * sizeof(T));
In file included from /home/jwalden/moz/after/js/src/dbg/dist/include/js/TracingAPI.h:11,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/GCPolicyAPI.h:47,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/RootingAPI.h:22,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/CallArgs.h:73,
                 from /home/jwalden/moz/after/js/src/jsapi.h:29,
                 from /home/jwalden/moz/after/js/src/vm/DebuggerMemory.h:10,
                 from /home/jwalden/moz/after/js/src/vm/DebuggerMemory.cpp:7,
                 from /home/jwalden/moz/after/js/src/dbg/js/src/Unified_cpp_js_src32.cpp:2:
/home/jwalden/moz/after/js/src/dbg/dist/include/js/HashTable.h:794:7: note: ‘class js::detail::HashTableEntry<js::HashMapEntry<JS::Value, unsigned int> >’ declared here
 class HashTableEntry
In file included from /home/jwalden/moz/after/js/src/dbg/dist/include/js/HashTable.h:19,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/TracingAPI.h:11,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/GCPolicyAPI.h:47,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/RootingAPI.h:22,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/CallArgs.h:73,
                 from /home/jwalden/moz/after/js/src/dbg/dist/include/js/CallNonGenericMethod.h:12,
                 from /home/jwalden/moz/after/js/src/NamespaceImports.h:15,
                 from /home/jwalden/moz/after/js/src/gc/Barrier.h:10,
                 from /home/jwalden/moz/after/js/src/vm/ArgumentsObject.h:12,
                 from /home/jwalden/moz/after/js/src/vm/GeneratorObject.h:10,
                 from /home/jwalden/moz/after/js/src/vm/GeneratorObject.cpp:7,
                 from /home/jwalden/moz/after/js/src/dbg/js/src/Unified_cpp_js_src33.cpp:2:
/home/jwalden/moz/after/js/src/dbg/dist/include/mozilla/PodOperations.h: In instantiation of ‘void mozilla::PodZero(T*) [with T = js::NativeIterator]’:
/home/jwalden/moz/after/js/src/vm/Iteration.cpp:578:15:   required from here
/home/jwalden/moz/after/js/src/dbg/dist/include/mozilla/PodOperations.h:32:9: warning: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘struct js::NativeIterator’ with no trivial copy-assignment; use assignment or value-initialization instead [-Wclass-memaccess]
   memset(aT, 0, sizeof(T));
In file included from /home/jwalden/moz/after/js/src/vm/JSCompartment-inl.h:14,
                 from /home/jwalden/moz/after/js/src/vm/JSObject-inl.h:32,
                 from /home/jwalden/moz/after/js/src/vm/ArrayObject-inl.h:15,
                 from /home/jwalden/moz/after/js/src/vm/GeneratorObject.cpp:11,
                 from /home/jwalden/moz/after/js/src/dbg/js/src/Unified_cpp_js_src33.cpp:2:
/home/jwalden/moz/after/js/src/vm/Iteration.h:32:8: note: ‘struct js::NativeIterator’ declared here
 struct NativeIterator

Fixing the problem by not using mozilla::PodZero

Historically you’d have to add every single member-initialization to your constructor, duplicating names and risking missing one, but C+11’s in-class initializers allow an elegant fix:

// Add " = nullptr" to initialize these function pointers.
struct AsmJSCacheOps
    OpenAsmJSCacheEntryForReadOp openEntryForRead = nullptr;
    CloseAsmJSCacheEntryForReadOp closeEntryForRead = nullptr;
    OpenAsmJSCacheEntryForWriteOp openEntryForWrite = nullptr;
    CloseAsmJSCacheEntryForWriteOp closeEntryForWrite = nullptr;

As long as you invoke a constructor, the members will be initialized. (Constructors can initialize a member to override in-class initializers.)

List-initialization using {} is also frequently helpful: you can use it to zero trailing (or all) members of an array or struct without naming/providing them:

class PreliminaryObjectArray
    static const uint32_t COUNT = 20;

    // All objects with the type which have been allocated. The pointers in
    // this array are weak.
    JSObject* objects[COUNT] = {}; // zeroes

    PreliminaryObjectArray() = default;

    // ...

Finally, C++ offers iterative-mutation functions to fill a container:

#include <algorithm>

// mozilla::Array's default constructor doesn't initialize array
// contents unless the element type is a class with a default
// constructor, and no Array overload exists to zero every
// element.  (You could pass 1024 zeroes, but....)
mozilla::Array<uint32_t, 1024> page; // array contents undefined

std::fill(page.begin(), page.end(), 0); // now contains zeroes
std::fill_n(page.begin(), page.end() - page.begin(), 0); // alternatively

After a long run of fixes to sundry bits of SpiderMonkey code to fix every last one of these issues last week, I’ve returned SpiderMonkey to warning-free with gcc (excluding imported ICU code). The only serious trickiness I ran into was a function of very unusual SpiderMonkey needs that shouldn’t affect code generally.

Fixing these issues is generally very doable. As people update to newer and newer gcc to build, the new -Wclass-memaccess warning that told me about these issues will bug more and more people, and I’m confident all these problems triggered by PodZero can be fixed.

mozilla::PodZero and mozilla::PodArrayZero are deprecated

PodZero and its array-zeroing variant PodArrayZero are ill-fitted to modern C++ and modern compilers. C++ now offers clean, type-safe ways to initialize memory to zeroes. You should avoid using PodZero and PodArrayZero in new code, replacing it with the initializer syntaxes mentioned above or with standard C++ algorithms to fill in zeroes.

As PodZero is used in a ton of places right now, it’ll likely stick around for some time. But there’s a good chance I’ll rename it to DeprecatedPodZero to highlight its badness and the desire to remove it. You should replace existing uses of it wherever and whenever you can.


Not a gluten-free trail

Tags: — Jeff @ 12:27

A desert bush with reddish-green berries

Apparent (?) prickly pear cacti

Prickly pear cactus

A green plant with lavender flowers

A thick, prickly pear-looking cactus with bright pink flowers that I don't think actually is prickly pear

Something that looks like a tall (and not wide) bright red lettuce

Fragile, pale yellow/pink bulbous flowers

Pasta, tortillas, and rice that are most definitely full of gluten

Sitting cool at mile 444 right now. I was aiming to be at the Sierras by June 19 or 27, but the snow course I signed up for then got canceled, so I’m in no rush. Might slow down for particular recommended attractions, but otherwise the plan is consistent 20+-mile days.


I’ve stopped hiking the PCT

Tags: — Jeff @ 16:47

Every year’s PCT is different. The path routinely changes, mostly as fresh trail is built to replace substandard trail (or no trail at all, if the prior trail was a road walk). But the reason for an ever-shifting PCT, even within hiking seasons, should be obvious to any California resident: fires.

The 2013 Mountain Fire near Idyllwild substantially impacted the nearby trail. A ten-mile stretch of trail is closed to hikers even today, apparently (per someone I talked to at the outfitter in Idyllwild) because the fire burned so hot that essentially all organic matter was destroyed, so they have to rebuild the entire trail to have even a usable tread. (The entire section is expected to open midsummer next year – too late for northbound thru-hikers, but maybe not for southbounders.)

A trail-closure sign

These circumstances lead to an alternate route for hikers to use. Not all do: many hikers simply hitchhike past the ten closed miles and the remote fifteen miles before them.

A temporary-reroute sign

But technically, there’s an official reroute, and I’ve nearly completed it. Mostly it involves lots of walking on the side of roads. The forest service dirt roads are rough but generally empty, so not the worst. The walking on a well-traveled highway with no usable shoulder, however, was the least enjoyable hiking I’ve ever done. (I mean ever.) I really can’t disagree with the people who just hitchhiked to Idyllwild and skipped it all.

I’ll be very glad to get back on the real trail several miles from now.


Guys! The Mojave Desert is hot and dry. Who knew?

Four days in, 77mi so far, at Julian overnight. Longest waterless stretch was 17.8mi, but I did end up only drinking the water I started with on the first 20mi day, so I suppose it was as if it were a 20mi waterless stretch, even if water was plentiful. (That said, this year was so rainy/snowy that a ton of water sources that usually would be dry, are still running now.)

Starting group picture

First rail crossing

Not a rattlesnake across the trail

A PCT sign that says

Unexploded military ordnance nearby! Woo!

An overlook, with other hiker trash in the foreground

View on a valley

Overnight campsite at sunset - good view, but very windy

Campsite in morning

Prickly pear-looking cactus

And, my overnight lodgings in Julian:

Overnight on the floor of a small restaurant


Back in a bit

Tags: , , , , — Jeff @ 05:00
Woman with an anxious look on her face, sitting in a seat on an airplane -- from that great classic, Airplane!
I’ve gotta get out of here

I tend to take either relatively brief vacations (a day or two at a time) or very long ones. Brief vacations serve specific purposes, so they only mentally recharge me a little. Only long vacations let me set my head straight. Recent long vacations have been:

I haven’t taken any long trips to unwind since 2014. Injuries (a persistent high ankle sprain ultimately requiring arthroscopic surgery, a stress fracture to the same foot) are partly to blame. Regardless, I haven’t fully decompressed in a very long time.

During the last weeks of the A.T. thru-hike, I stayed at a hostel with a Pacific Crest Trail thru-hiker guidebook. When I finished reading it, I knew I would hike the PCT. I wasn’t sure when, but I knew it would happen.

This year’s the year.

Conventional wisdom holds that if you can hike the ~2175mi A.T. in N months, the ~2650mi PCT will take N – 1 months. (The A.T. is a rugged trail of rocks and roots; the PCT is a well-graded horse trail.) Obviously this breaks down eventually, and I suspect a relatively-fast 137-day A.T. pace passes that point. I’m guessing I’ll need four months: 240 hours of PTO (Nᴇᴡ Hɪɢʜ Sᴄᴏʀᴇ!), then three months’ unpaid leave, including a cushion. I’m guessing I’ll be done by mid-September.

The A.T. is generally non-technical. No special equipment is required (except during snow extremes at the north end). Civilization is almost always nearby. The PCT is more technical, with a trail unmarked by omnipresent white blazes or signs regularly identifying the PCT. Lingering snow may completely obscure the trail. Swollen, icy creek crossings present dangers I only approached a single day on the A.T. Resupply locations are less frequent and comprehensive. It’s necessary to mail food to oneself at certain points, to resupply at all at them.

New equipment I've had to pick up for the PCT: crampons; wraparound, UV-blocking, polarized sunglasses; crampons
With trekking pole/ice pick in hand, I’m ready for my next political assassination

The learning curve for the PCT is steeper than for the A.T. Some people might worry about this, but I won’t be one of them. Worrying isn’t helpful: why allow it take root?

Caution and preparedness are different matters. For example, I know ~zero about safely hiking through alpine snow. And this year was a roughly every-six-year snow year, maybe worse in localized areas. But I can address that with training. There should be room to learn other PCT peculiarities in the first few hundred miles.

A graph of California north/central/south snowpack over each season, for various winter seasons; 1982-1983 establishes a high mark, 2016-2017/2010-2011/2005-2006 are high but not historically so, and 2013-2014 and 2014-2015 are around the recorded minimums

My only uncontrollable concern is that foot stress fracture. It happened two and a half years ago; the fracture has healed; and I’ve walked, run, and hiked on it for a year. A sports medicine doctor cleared me to walk to Canada on it.  (I was very specific about doing exactly that.) But my right big toe still isn’t 100% flexible, its ligaments semi-regularly ache during or after exercise, and it sometimes bruises. I’ll do what I can about this through cushioned socks, ongoing flexibility exercises, and moderating pace if needed. But I can’t eliminate the risk that it might significantly slow me down or even stop me.

If all goes well, I’ll return in September, mentally refreshed, with a peculiarly developed endurance for walking and very few fast-twitch muscle fibers. 🙂 I’ve turned off Bugzilla request capabilities, so don’t try asking me to review patches. If you must contact me, email might work. I’ll rely heavily on server-side filters to keep the firehoses hidden, but that doesn’t mean I’ll necessarily see an email. If possible send reviews and questions to the usual suspects. Moreover, the PCT is much more remote than the A.T., so I’ll likely go longer between email access than I did on the A.T. In places, a two-week delay in responding would not be unusual. (But I’ll try to keep people updated on where I am whenever possible, specifically to reduce the risks and dangers in a moronically-avoidable 127 Hours-style rescue snafu. I put the best odds on Twitter updates because they’re quickest. But I’ll post some pictures here as well to one-up roc. “My country’s scenery beat up your country’s scenery”)

I’m currently on my way to San Diego. Some helpful souls who love the trail (“trail angels”, in the vernacular) offer aspiring thru-hikers a place to stay just before, and a ride to the start the day of, their thru-hikes. I’ll stay tonight with them. Tomorrow the rubber hits the trail. It should be good.

Older »