@@ -967,6 +967,61 @@ std::optional<SnapshotConfig> ReadSnapshotConfig(const char* config_path) {
967967 return result;
968968}
969969
970+ // Find bindings that have been loaded by internalBinding() but the external
971+ // reference method have not been called. This requires that the caller
972+ // match the id passed into their NODE_BINDING_CONTEXT_AWARE_INTERNAL() and
973+ // NODE_BINDING_EXTERNAL_REFERENCE() calls. Note that this only serves as a
974+ // preemptive check. Binding methods create the actual external references
975+ // (usually through function templates) and there's currently no easy way
976+ // to verify at that level of granularity. See "Registering binding functions
977+ // used in bootstrap" in src/README.md.
978+ bool ValidateBindings (Environment* env) {
979+ std::set<std::string> registered;
980+ #define V (modname ) registered.insert(#modname);
981+ EXTERNAL_REFERENCE_BINDING_LIST (V)
982+ #undef V
983+
984+ std::set<std::string> bindings_without_external_references = {
985+ " async_context_frame" ,
986+ " constants" ,
987+ " symbols" ,
988+ };
989+
990+ std::set<std::string> unregistered;
991+ for (auto * mod : env->principal_realm ()->internal_bindings ) {
992+ if (registered.count (mod->nm_modname ) == 0 &&
993+ bindings_without_external_references.count (mod->nm_modname ) == 0 ) {
994+ unregistered.insert (mod->nm_modname );
995+ }
996+ }
997+
998+ if (unregistered.size () == 0 ) {
999+ return true ;
1000+ }
1001+
1002+ FPrintF (
1003+ stderr,
1004+ " \n ---- snapshot building check failed ---\n\n "
1005+ " The following bindings are loaded during the snapshot building process,"
1006+ " but their external reference registration methods have not been "
1007+ " called:\n\n " );
1008+ for (auto & binding : unregistered) {
1009+ FPrintF (stderr, " - %s\n " , binding);
1010+ }
1011+ FPrintF (stderr,
1012+ " \n If the binding does not have any external references, "
1013+ " add it to the list of bindings_without_external_references "
1014+ " in src/node_snapshotable.cc.\n "
1015+ " Otherwise, make sure to call NODE_BINDING_EXTERNAL_REFERENCE() "
1016+ " with an appropriate register method for the binding, "
1017+ " and add it to EXTERNAL_REFERENCE_BINDING_LIST in "
1018+ " src/node_external_reference.h"
1019+ " \n\n See \" Registering binding functions used in bootstrap\" "
1020+ " in src/README.md for more details."
1021+ " \n ----\n\n " );
1022+ return false ;
1023+ }
1024+
9701025ExitCode BuildSnapshotWithoutCodeCache (
9711026 SnapshotData* out,
9721027 const std::vector<std::string>& args,
@@ -1032,6 +1087,11 @@ ExitCode BuildSnapshotWithoutCodeCache(
10321087 if (exit_code != ExitCode::kNoFailure ) {
10331088 return exit_code;
10341089 }
1090+
1091+ if (snapshot_type == SnapshotMetadata::Type::kDefault &&
1092+ !ValidateBindings (env)) {
1093+ return ExitCode::kStartupSnapshotFailure ;
1094+ }
10351095 }
10361096
10371097 return SnapshotBuilder::CreateSnapshot (out, setup.get ());
0 commit comments