sourcemod icon indicating copy to clipboard operation
sourcemod copied to clipboard

Natives is not bounds correctly when OnPluginStart triggers after server launch

Open CrazyHackGUT opened this issue 4 years ago • 7 comments

Help us help you

  • [X] I have checked that my issue doesn't exist yet.
  • [X] I have tried my absolute best to reduce the problem-space and have provided the absolute smallest test-case possible.
  • [X] I can always reproduce the issue with the provided description below.

Environment

  • Operating System version: Linux/Windows
  • Game/AppID (with version if applicable): 232330, 232250, 740
  • Current SourceMod version: 1.10.0
  • Current SourceMod snapshot: 6502
  • Current Metamod: Source snapshot: 1.11.0-dev+1144
  • [X] I have updated SourceMod to the latest version and it still happens.
  • [X] I have updated SourceMod to the latest snapshot and it still happens.
  • [X] I have updated SourceMM to the latest snapshot and it still happens.

Description

It looks like issue is in SM, but I'm not sure. When the first plugin (SMBug_with_natives.sp) has some forward and native, and the forward is called in OnPluginStart() after complete server launch, natives are "not bounded" yet. For example, the second plugin (SMBug_without_natives.sp) calls native from the first plugin. After server launch, everything works as expected: server_start But when we try to reload the plugin or unload and load it manually, we receive the "Native is not bound" error: plugin reload

Problematic Code (or Steps to Reproduce)

SMBug_with_natives.sp (first plugin)

#include <sourcemod>
#include <functions>
#include <handles>

Handle g_hForward;

public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
    CreateNative("MyNative", _MyNative);
    g_hForward = CreateGlobalForward("MyForward", ET_Ignore);

    RegPluginLibrary("my_library");

    return APLRes_Success;
}

public void OnPluginStart()
{
    // perform something initialization
    Call_StartForward(g_hForward);
    Call_Finish();
}

public int _MyNative(Handle hPlugin, int iParamCount)
{
    // do some hard work
    return 1;
}

SMBug_without_natives.sp (second plugin)

#include <sourcemod>
#include <functions>
#include <handles>

native int MyNative();

public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
    MarkNativeAsOptional("MyNative");
    return APLRes_Success;
}

public void OnLibraryAdded(const char[] szName)
{
    LogMessage("OnLibraryAdded(): %s", szName);
}

public void MyForward()
{
    LogMessage("MyForward()");
    LogMessage("MyForward(): calling a native... result %x", MyNative());
}

CrazyHackGUT avatar Apr 16 '21 14:04 CrazyHackGUT

You should wait until OnAllPluginsLoaded to access other plugins or fire forwards to ensure any changes have propagated which were caused by your plugin loading. So try moving the code in OnPluginStart in SMBug_with_natives.sp to OnAllPluginsLoaded. That should fix your issue.

peace-maker avatar Apr 16 '21 14:04 peace-maker

In my case, i has forward named as XXXX_OnConfigLoaded. Config reads after plugin starting and by server command. You suggest move config reading (include database connecting and many another initialization stuff) into OnAllPluginsLoaded?

CrazyHackGUT avatar Apr 16 '21 14:04 CrazyHackGUT

I tested. It solves the issue, but this don't answers, why native is not bounded when OnPluginStart() fires, if we perform binding operations before this forward calls. Exactly for natives availability in another stages.

CrazyHackGUT avatar Apr 16 '21 14:04 CrazyHackGUT

There is an underlying issue here which is that because you're using an inline native declaration rather than a correctly formatted include file with dependency information, SM has no idea what the relationship between the plugins is which is leaving things in an inconsistent state after you unload/reload the native providing plugin.

Normally SM will sequence load operations in such a way that all depended-upon plugins are loaded before the plugins that depend upon them, which is what makes natives available in OnPluginStart as long as they're registered in AskPluginLoad. That all said, there was another report a few weeks back of reloading a plugin providing natives not re-binding them automatically in dependant plugins.

I'd be interested if you still get the problem when using a correct SharedPlugin declaration alongside the native declaration.

asherkin avatar Apr 16 '21 14:04 asherkin

I received this issue with SharedPlugin declaration in another project. I perform support for plugin what written by another SP scripter. Sometimes users reports issue with plugin reloading. Today i received this report:

sm_rcon sm plugins reload materialadmin.smx
L 04/16/2021 - 16:17:02: [basecommands.smx] "Console<0><Console><Console>" console command (cmdline "sm plugins reload materialadmin.smx")
L 04/16/2021 - 16:17:02: [vip/VIP_Core.smx] OnLibraryAdded: materialadmin
L 04/16/2021 - 16:17:02: [SM] Exception reported: Native is not bound
L 04/16/2021 - 16:17:02: [SM] Blaming: ma_adminmenu.smx
L 04/16/2021 - 16:17:02: [SM] Call stack trace:
L 04/16/2021 - 16:17:02: [SM] [0] MAGetConfigSetting
L 04/16/2021 - 16:17:02: [SM] [1] Line 90, C:\Users\Slava\Downloads\sourcemod-1.10.0-git6460-windows\addons\sourcemod\scripting\ma_adminmenu.sp::MAOnConfigSetting
L 04/16/2021 - 16:17:02: [SM] [3] Call_Finish
L 04/16/2021 - 16:17:02: [SM] [4] Line 486, materialadmin/native.sp::FireOnConfigSetting
L 04/16/2021 - 16:17:02: [SM] [5] Line 1349, materialadmin/function.sp::VerifyServerID
L 04/16/2021 - 16:17:02: [SM] [6] Line 88, materialadmin/config.sp::ReadConfig
L 04/16/2021 - 16:17:02: [SM] [7] Line 283, C:\Users\Slava\Downloads\sourcemod-1.10.0-git6460-windows\addons\sourcemod\scripting\materialadmin.sp::OnPluginStart
[SM] Plugin Material Admin reloaded successfully.

This can be caused because plugin with required native compiled with undefined REQUIRE_PLUGIN? https://github.com/SB-MaterialAdmin/NewServer/blob/1b7f0aa34df7a87bd976543d9abaa39279eadbe4/addons/sourcemod/scripting/ma_adminmenu.sp#L38-L41 https://github.com/SB-MaterialAdmin/NewServer/blob/1b7f0aa34df7a87bd976543d9abaa39279eadbe4/addons/sourcemod/scripting/include/materialadmin.inc#L6-L15

CrazyHackGUT avatar Apr 16 '21 14:04 CrazyHackGUT

Ok, i tested now. Looks like issue related with SharedPlugin. Currently, i has this code:

// plugin 1 (with native declaration)
#include <sourcemod>
#include <functions>
#include <handles>

Handle g_hForward;

public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
    CreateNative("MyNative", _MyNative);
    g_hForward = CreateGlobalForward("MyForward", ET_Ignore);

    RegPluginLibrary("my_library");

    return APLRes_Success;
}

public void OnPluginStart()
{
    // perform something initialization
    Call_StartForward(g_hForward);
    Call_Finish();
}

public int _MyNative(Handle hPlugin, int iParamCount)
{
    // do some hard work
    return 1;
}

// plugin 2 (calls native from plugin 1)
#include <sourcemod>
#include <functions>
#include <handles>

native int MyNative();
public SharedPlugin __pl_my_library = {
    name = "my_library",
    file = "SMBug_with_natives.smx",
    required = 0
};

public APLRes AskPluginLoad2(Handle hMySelf, bool bLate, char[] szBuffer, int iBufferLength)
{
    MarkNativeAsOptional("MyNative");
    return APLRes_Success;
}

public void OnLibraryAdded(const char[] szName)
{
    LogMessage("OnLibraryAdded(): %s", szName);
}

public void MyForward()
{
    LogMessage("MyForward()");
    LogMessage("MyForward(): calling a native... result %x", MyNative());
}

When i compile plugin with required = 1, reload plugin 1 with native performs correctly, without any errors, BUT forward in plugin 2 doesn't fired. When i use required = 0, forward fires, but fails with "Native is not bound" error. image

CrazyHackGUT avatar Apr 16 '21 14:04 CrazyHackGUT

With required = 1 plugin 1 is fully loaded before plugin 2, so plugin 2's use of the forward hasn't been registered yet by the time it is fired.

It looks like there is probably a bug with the required = 0 case, given the order that plugin 1 is doing things it doesn't seem like plugin 2's use of the forward should be registered before it's natives have been bound - optional or not. PluginSys is probably just doing something in the wrong order in the late-load case.

asherkin avatar Apr 16 '21 14:04 asherkin