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