c0000005 Crash on closing.

SuperZooper

New Member
I recently wrote a script that just fuzes text together and writes it to an obs source. From a bit of testing, it seems to be the cause of a c0000005 I am getting. Here is the info from the thread that crashes. I suspect it has something to do with not releasing an object correctly.

Code:
Unhandled exception: c0000005
Date/Time: 2021-10-26, 10:18:54
Fault address: 7FFF8E131C09 (c:\program files\obs-studio\obs-plugins\64bit\obs-text.dll)
libobs version: 27.1.3 (64-bit)
Windows version: 10.0 build 19043 (release: 2009; revision: 1288; 64-bit)
CPU: AMD Ryzen 5 2600 Six-Core Processor          


Thread 12C0: (Crashed)
Stack            EIP              Arg0             Arg1             Arg2             Arg3             Address
000000D2444FF150 00007FFF8E131C09 0000000000000000 00007FFF8E1CD308 000000D2444FF1A8 00000239062E23E0 obs-text.dll!<lambda_880baa1155d709808c7f0b661ebf8f8d>::operator()+0x99
000000D2444FF180 00007FFF8E17E6DC 000002395F9FAE70 000000D2444FF7A0 0000000000000000 0000000000000000 obs.dll!obs_source_destroy+0x20c
000000D2444FF280 00007FFF8E1910EF 000000D2444FF7A0 00000000FFFFFFFF 0000000000000000 0000000000000160 obs.dll!obs_free_data+0x9f
000000D2444FF2B0 00007FFF8E195203 0000000000000000 000000D2444FF580 000000D2444FF7A0 000000D2444FF6E0 obs.dll!obs_shutdown+0x433
000000D2444FF300 00007FF71909B16A 000000D2444FF3D0 000000D200000000 00007FF719345ED0 000002395F94F5F0 obs64.exe!OBSApp::~OBSApp+0x5a
000000D2444FF330 00007FF7190A718E 0000000000000000 000002395F9743F0 0000023900000000 000002395F971EF0 obs64.exe!run_program+0x93e
000000D2444FF6A0 00007FF7190A9290 0000000000000000 0000000000000000 0000000000000000 FFFFFFFFFFFFFFFF obs64.exe!main+0x6c0
000000D2444FF870 00007FF71923E3D7 0000000000000000 0000000000000000 0000000000000000 0000000000000000 obs64.exe!WinMain+0x157
000000D2444FF900 00007FF71923DC96 0000000000000000 0000000000000000 0000000000000000 0000000000000000 obs64.exe!__scrt_common_main_seh+0x106
000000D2444FF940 00007FFF98E17034 0000000000000000 0000000000000000 0000000000000000 0000000000000000 kernel32.dll!0x7fff98e17034
000000D2444FF970 00007FFF99702651 0000000000000000 0000000000000000 0000000000000000 0000000000000000 ntdll.dll!0x7fff99702651

Here is the code for the script that I think is causing the crash. I think the problem will be somewhere in the second part of the code or in `write_output`.

Python:
import obspython as obs

TSourceOutputName = "" # Text source being written to in OBS
indexFile = "" # List of input text files to fuze
outputFile = "" # Path to the output file
formattingString = "" # Formatting string for the output text
lastString = "" # Compare last and new string
refreshTime = 5 # Refresh time of the text source
sleepTime = 20 # The polling rate when not active
timerSpeed = refreshTime
fileOutput = True

# ACTUAL TEXT UPDATING ------------------------------------------------------------

def update_text(props, prop):
    global TSourceOutputName
    global indexFile
    global formattingString
    global lastString
    global sleepTime

    # Read every line of the file at indexFile and add it to an array
    paths = []

    with open(indexFile) as file:
        a = file.readlines()
        for line in a:
            paths.append(line.strip())
           
    # Add the text of every file in paths to an array called texts
    texts = []
    for path in paths:
        with open(path) as file:
            texts.append(file.read())

    outputText = formattingString
    # Format the output text
    for i in range(len(texts)):
        if "%" + str(i+1) in outputText:
            outputText = outputText.replace("%" + str(i+1), texts[i])

    # Update the text source only if it has changed
    if outputText != lastString:
        lastString = outputText
        write_output(outputText)

# Function to either write to a file, or to the text source in OBS
def write_output(message):
    global fileOutput
    global outputFile
    global TSourceOutputName

    # Create a new file called fuzed.txt at the path spectifed in outputFile and write the message to it, then close it
    if fileOutput:
        with open(outputFile, "a") as file:
            # Clear the file
            file.truncate(0)
            # Write the message to the file
            file.write(message)

    else:
        settings = obs.obs_data_create()
        obs.obs_data_set_string(settings, "text", message)
        obs.obs_source_update(obs.obs_get_source_by_name(TSourceOutputName), settings)
        obs.obs_data_release(settings) # #NoMemLeaks
   
# OBS SETTINGS STUFF------------------------------------------------------------

def script_description():
    return "Fuze text files and inject the output into a text source.\nThe Index file directory should be a list of file directorys for the text files you want to merge. Each file on its own line.\nUse `%I` where I is the number of the file you gave in (1 indexed) in the formating string to define how you want the outputed text to look. EX: `%1 - %2 / Song by: %3` \n\nBy SuperZooper3"

def script_update(settings):
    global TSourceOutputName
    global indexFile
    global refreshTime
    global formattingString
    global sleepTime
    global outputFile
    global fileOutput

    TSourceOutputName = obs.obs_data_get_string(settings, "TSourceOutputName")
    indexFile = obs.obs_data_get_string(settings, "indexFile")
    formattingString = obs.obs_data_get_string(settings, "formattingString")
    refreshTime = obs.obs_data_get_int(settings, "refreshTime")
    sleepTime = obs.obs_data_get_int(settings, "sleepTime")
    outputFile = obs.obs_data_get_string(settings, "outputFile")
    fileOutput = obs.obs_data_get_bool(settings, "fileOutput")

    # Update the refresh timer
    obs.timer_remove(refresh_text)
   
    if refreshTime > 0  and indexFile != "" and formattingString != "" and (not fileOutput  and TSourceOutputName != "" or (fileOutput and outputFile != "")):
        obs.timer_add(refresh_text, refreshTime * 1000)

def script_defaults(settings): # Sets the defaults for the values in the obs editor
    obs.obs_data_set_default_int(settings, "refreshTime", 5)
    obs.obs_data_set_default_int(settings, "sleepTime", 20)

# This needs to be here for the refresh button to work
def refresh_text():
    global timerSpeed
    # Update the poling rate to the apporiate value
    if obs.obs_source_active(obs.obs_get_source_by_name(TSourceOutputName)) and refreshTime != timerSpeed:
        obs.timer_remove(refresh_text)
        obs.timer_add(refresh_text, refreshTime * 1000)
        timerSpeed = refreshTime
    elif not obs.obs_source_active(obs.obs_get_source_by_name(TSourceOutputName)) and timerSpeed != sleepTime:
        obs.timer_remove(refresh_text)
        obs.timer_add(refresh_text, sleepTime * 1000)
        timerSpeed = sleepTime

    # Update the text
    if obs.obs_source_active(obs.obs_get_source_by_name(TSourceOutputName)):
        update_text(props="", prop="")

def script_properties(): # Get the property boxes so we cant use them here
    props = obs.obs_properties_create()

    # All of the input boxes

    # The text source
    p = obs.obs_properties_add_list(props, "TSourceOutputName", "Text Output Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
    sources = obs.obs_enum_sources()
         
    if sources is not None:
        for source in sources:
            source_id = obs.obs_source_get_unversioned_id(source)
            if source_id == "text_gdiplus" or source_id == "text_ft2_source":
                name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
               
        obs.source_list_release(sources)

    obs.obs_properties_add_path(props, "indexFile", "Index File Directory", obs.OBS_PATH_FILE, "", "")
    obs.obs_properties_add_text(props, "formattingString", "Formatting String", obs.OBS_TEXT_DEFAULT)
    obs.obs_properties_add_int(props, "refreshTime", "Refresh Time", 1, 999, 1)
    obs.obs_properties_add_int(props, "sleepTime", "Sleep Refresh Time", 1, 999, 1)
    obs.obs_properties_add_path(props, "outputFile", "Output File (.txt)", obs.OBS_PATH_FILE, "", "")
    obs.obs_properties_add_bool(props, "fileOutput", "Output to File (true) or to source (false)")

    # Refresh button
    obs.obs_properties_add_button(props, "button", "Refresh", update_text)

    return props

Log file: https://obsproject.com/logs/vUgnwOeVLBIHUvqF
 

upgradeQ

Member
You forgot to release a source several times, instead of writing like this :
obs.obs_source_active(obs.obs_get_source_by_name(TSourceOutputName))
write this:

Python:
target_source = obs.obs_get_source_by_name(TSourceOutputName)
obs.obs_source_active(target_source)
obs.obs_source_release(target_source)
 
Top