Resolving WinCC C0000005 ACCESS_VIOLATION Script Crashes

David Krause17 min read
SiemensTroubleshootingWinCC
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Problem Overview

The exception code C0000005 ACCESS_VIOLATION raised inside the WinCC scripting runtime terminates script.exe on a WinCC client or server. The crash text is written to <WinCC_Project>\Scripts\log\script.log and to the Windows Application event log. After the first fault, all global C-scripts stop executing on the affected machine. The image is processed in the background service script.exe, which is launched by the WinCC Runtime as soon as the first @-script is triggered. When the service crashes it is restarted by the WinCC runtime, but the fault re-occurs within seconds whenever the triggering event fires again, producing a tight loop of exceptions until the project is reloaded or the action is removed.

The problem has been observed on:

  • WinCC V6.2 SP3 (legacy release, still installed on many operating stations)
  • WinCC V7.0 SP1, SP2 and SP3 (RT and RT64 client builds)
  • WinCC V7.2, V7.3 and V7.4 (when the project was originally migrated from V6.2/V7.0 and the legacy C-action code is still present)

The crash is independent of the HMI station role: it occurs on single-user stations, on WinCC servers running the project as a server, and on WinCC clients that connect to a remote server. The error is non-deterministic: the same project can run for hours or days before the first fault, then crash repeatedly.

Symptoms

Engineers typically see one or more of the following:

  • The WinCC runtime goes into a "Not Ready" state. Pictures stay open but no values update, and no user input is processed by actions.
  • APCdiag (Action Performance Diagnosis) shows the action that triggered the fault as "aborted".
  • The Windows Event Viewer (Application log) records an Error of source Application Error and faulting module script.exe, version range typical of the installed WinCC build.
  • Subsequent script calls are dispatched to a freshly-started script.exe instance which then crashes again at the next trigger.
  • Tag logging and alarms keep running because they use CCAlgRtServer.exe and CCMsgServer.exe, not script.exe. Only the action layer is broken.
Important: A C0000005 from WinCC is not a Windows fault - it is generated by the C runtime of the WinCC scripting engine. The exception is wrapped by the WinCC error reporter and written verbatim to script.log. Treat the file as the authoritative crash dump, not the Windows event log.

Exception Code Reference

The Windows structured exception code 0xC0000005 is defined as EXCEPTION_ACCESS_VIOLATION. The exception is raised when a thread attempts to read from, write to, or execute a virtual address for which it has no permission under the current process state. In the WinCC context the access is almost always a read or write through a stale pointer obtained from a tag handle, a temporary string buffer, or a freed object.

Field Value in the script.log Meaning
Exception Code 0xC0000005 EXCEPTION_ACCESS_VIOLATION
Faulting Address 0x7C9109F9 (ntdll)
0x100413CB (AKTSTEU)
0x1004171D (AKTSTEU)
Address where the thread faulted
CS:EIP 001B:7C9109F9 Code segment : Instruction pointer
DS / ES 0023 Default user-mode data segment
SS:ESP 0023:0353FD1C Stack segment : stack pointer
Flags 00010246 EFLAGS at the time of fault

For a Microsoft overview of the C0000005 access violation class see the official Microsoft Learn Inside C0000005 reference.

Root Cause

The crash has two distinct signatures. Both originate from the C-action interpreter of WinCC, but they are triggered by different patterns.

Signature A - wcsncpy inside SCSIVA~2.DLL

The call stack shows:

ntdll.dll!wcsncpy+0x49A
ntdll.dll!wcsncpy+0x2CD
msvcrt.dll!free+0xCD
SCSIVA~2.DLL!0x00008ED0
SCSIVA~2.DLL!0x00008389
SCSIVA~2.DLL!0x000055FF
SCSIVA~2.DLL!0x00007EEF
CThreadSafeObject::Release+0x3F
CThreadExecuteCall::~CThreadExecuteCall+0x7C
CThreadExecuteCall::operator=+0xFD
CThreadSafeObject::Release+0x3F
CAsyncCallList::OnMessage+0x62
CThread::OnRun+0x2E
CThread::OnExitInstance+0x44
msvcrt.dll!endthreadex+0x44
msvcrt.dll!endthreadex+0xD8
kernel32.dll!GetModuleFileNameA+0x1B4

SCSIVA~2.DLL is the Siemens ACE (ActiveX Control Embedding) helper that exposes OLE Automation / DCOM interfaces from CCScript.exe to the C-action runtime. The combination of wcsncpy called from free indicates a use-after-free in the lifetime management of an ACE object. WinCC allocates a temporary BSTR or wide-string buffer to pass a tag value to a C action, hands the buffer to the action, and the action returns a value that the runtime is supposed to free. If the value is freed by both the action and the runtime, or freed once with the wrong allocator, free() walks an invalid heap block and the second free is performed inside wcsncpy, which copies from a dangling pointer.

Signature B - AKTSTEU.dll GetValueBuffer

The call stack shows:

AKTSTEU.dll!0x000403CB
AKTSTEU.dll!GetValueBuffer+0x1EF2
Ordinal3180+0x10E
msvcrt.dll!endthreadex+0x44
msvcrt.dll!endthreadex+0xD8
kernel32.dll!GetModuleFileNameA+0x1B4

or

AKTSTEU.dll!0x0004071D
AKTSTEU.dll!GetValueBuffer+0x1EBF
Ordinal3180+0x10E
...

AKTSTEU.dll is the WinCC action control DLL. It implements the action scheduler, the trigger evaluation engine, and the bridge between a tag event and the C-action compiler output. GetValueBuffer is the function that reads the current value of the trigger tag at the moment the action fires. The crash at offset 0x000403CB with ECX = 0x00000000 and EDX = 0x00000014 is a NULL pointer dereference on the tag's internal value buffer, which means the trigger tag was deleted, renamed, or had its data type changed after the action was compiled.

Both signatures share one common trigger: a C action with a timer trigger, a tag trigger on a non-existent tag, or an action that has been compiled against an older picture tree and is now being re-dispatched after a project re-import.

Why Timer-Based C-Scripts Trigger the Fault

A WinCC C-action can be triggered by:

  1. A tag change (standard pattern, lowest risk)
  2. A picture open or picture change event
  3. A keyboard or mouse event
  4. A timer event (cyclic trigger)
  5. Hotkey or "once" event

The timer trigger is the most common root cause of C0000005. In a default WinCC V6.2 / V7.0 install, the C action runtime is single-threaded per project, but the WinCC picture runtime is multi-threaded. When a C action is triggered by a 1-second timer, the action is dispatched once per second, but each dispatch allocates a value buffer, compiles the return type, and frees both the input and the output buffer. If the C action contains a string assignment (char* or BSTR) inside a hot path, the buffer lifetime is short enough that a previously freed block is reused by the allocator and re-freed at the next cycle. The result is the free+0xCD crash inside wcsncpy.

When the same logic is moved to a tag-change trigger, the dispatch rate drops to the actual change rate of the tag, the lifetime of the buffer is the time between two real changes (typically hundreds of milliseconds or more), and the allocator does not return the freed block to a fresh allocation, so the use-after-free never occurs. This is the empirical workaround reported in the field: replacing a 1-second timer trigger with a tag-change trigger eliminates the fault immediately.

Diagnostic Procedure

  1. Capture the crash text. Open the project path
    C:\Program Files (x86)\Siemens\WinCC\WinCCProjects\<project>\Scripts\log\script.log
    Copy the last three exception blocks. The first word after FAULTING MODULE: identifies the signature:
    • ntdll.dll + wcsncpy = Signature A (use-after-free in ACE)
    • AKTSTEU.dll + GetValueBuffer = Signature B (stale tag handle)
  2. Enable ApDiag logging. ApDiag is shipped with WinCC V6.2 and later and is located in the WinCC installation directory. Open a WinCC project context and run
    Start > SIMATIC > WinCC > Tools > ApDiag.exe
    Set the filter to capture all actions, click Start Trace, and reproduce the crash. ApDiag writes the action name, the trigger type, the trigger tag, the dispatch time, and the return value. The last action in the trace is the one that faulted.
  3. List all global C actions and their triggers. In the WinCC Explorer, expand Global Script > C-Editor. For every action, note the trigger type, the trigger tag (if any), the picture it belongs to, and the last modification date. Sort by trigger type and identify every action with a timer trigger.
  4. Compare the trigger tag with the tag database. For every C action with a tag trigger, open the tag in the WinCC Tag Management. If the tag no longer exists, the trigger field references a deleted object and the action will fault the next time it fires.
  5. Check the project's data type changes. If a tag was changed from BOOL to WORD or from FLOAT to DOUBLE, the compiled action contains a call to a typed accessor that no longer matches the new type. The WinCC compiler does not always re-emit the call, so the action keeps the old accessor and faults inside GetValueBuffer.
  6. Inspect the picture tree. If a C action is attached to a picture, check that the picture file (PDL) still exists in the project's Grafic directory. Renaming a picture without re-binding the action leaves the action pointing to a non-existent picture object, and the first dispatch re-allocates an invalid pointer.

Step-by-Step Resolution

Step 1 - Stop the runtime

Close the WinCC runtime on the affected station. Confirm that script.exe is no longer running in Task Manager. Make a full backup of the project directory, including the project database, the Grafic directory, the Scripts directory, and the Library directory.

Step 2 - Remove the timer trigger

Open the action that was last listed in ApDiag, change the trigger from Standard cycle 1s (or any cyclic trigger) to a Tag trigger. Pick a tag that already changes at least every few seconds. If no suitable tag exists, create a dummy internal tag and write to it from a separate, low-priority VBScript that uses HMIRuntime.Tags("MyHeartbeat").Write in a 5-second loop. Do not start a C action with a 1-second cycle - use 5 seconds or longer if a cyclic trigger is unavoidable.

Step 3 - Repair stale tag references

For every action that uses a tag trigger, confirm the tag exists, has the same data type, and has the same address. If a tag has been renamed, update the action and recompile with File > Compile All in the C-Editor. If a tag has been deleted, replace it with a valid tag or disable the action.

Step 4 - Eliminate string manipulation in hot paths

C actions that perform strcpy, wcscpy, memcpy, or sprintf on a tag value are the highest-risk operations. Replace them with the WinCC-supplied string helpers:

// Instead of strcpy, use the safe wrapper provided by the WinCC API
const char* src = GetTagChar(lpszPictureName, "TagName");
char dest[256];
strncpy(dest, src ? src : "", sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
SetTagChar(lpszPictureName, "DestTag", dest);

The same pattern applies to GetTagFloat, SetTagFloat, GetTagWord, and the typed accessors. Always bound the destination buffer and always check the return pointer before copying.

Step 5 - Recompile and re-link

From the C-Editor, run File > Compile All, then File > Link All. If the C-Editor reports a linking error against apsvar.lib or akttapi.lib, the project has a corrupt action cache. Close the project, delete the generated *.c and *.obj files in the ScriptLib directory, reopen the project, and recompile.

Step 6 - Install the latest Hotfix

Apply the latest WinCC V7.x hotfix from the Siemens Industry Online Support portal. The relevant hotfix bundles for C0000005 in script.exe are:

WinCC Version Hotfix / Patch Notes
V6.2 SP3 WinCC V6.2 SP3 Hotfix 14 (and later) Includes the ACE/ScSiva lifetime fix
V7.0 SP3 WinCC V7.0 SP3 Hotfix 11 (and later) Fixes AKTSTEU tag-handle invalidation
V7.2 WinCC V7.2 Upd 1 + Hotfix 6 Replaces the legacy string allocator
V7.3 WinCC V7.3 Upd 1 + Hotfix 4 Replaces the legacy string allocator
V7.4 SP1 WinCC V7.4 SP1 Upd 1 Default already contains the fix

Download from the Siemens Industry Online Support portal, search for entry ID 109757946 ("Why does the script error 'C0000005 ACCESS_VIOLATION' appear in the script.log?") and follow the attached hotfixes.

Verification

After the changes are applied, verify the fix in five steps:

  1. Start the WinCC runtime and let it run for 30 minutes with the previous trigger conditions. Confirm that script.log does not grow.
  2. Open ApDiag and confirm that the action that was last listed in the previous crash trace is no longer aborted.
  3. Watch the Windows Application event log. There must be no Application Error with faulting module script.exe for at least 24 hours of continuous runtime.
  4. Use tasklist /fi "imagename eq script.exe" to confirm that the script.exe PID does not change every few seconds. A stable PID means the process is no longer being restarted.
  5. Force a hot reload: close the runtime, reopen it, and confirm that all actions fire without exception for the first hour of operation.

Troubleshooting Matrix

Symptom Likely Cause Action
Stack points to wcsncpy + SCSIVA~2.DLL Use-after-free in ACE string lifetime Install WinCC hotfix, remove timer triggers, recompile
Stack points to AKTSTEU.dll!GetValueBuffer Stale tag handle (renamed/deleted/changed type) Verify the tag exists, fix the data type, recompile
ECX = 0x00000000 in AKTSTEU crash NULL tag value buffer Check the tag is online and the PLC connection is up
EDX contains ASCII text such as 0x004F0044 Buffer interpreted as DWORD when it is a string Re-bind the tag with the correct data type
ECX = 0x69617254 ("Tari" in ASCII) Tag name read past end of buffer Tag name is empty - rename the tag and re-link the action
Crashes occur at the same time of day External scheduler (Task Scheduler, antivirus scan) Disable scheduled tasks that scan the WinCC directories
Crashes occur only on a redundant standby server Standby receives no tag updates, buffer is reused Use tag-change trigger, not timer trigger
Crashes occur after project re-import from V6.2 to V7.x Generated C code references old picture object IDs Re-create the actions in the new project rather than re-importing

Long-Term Prevention

  • Avoid timer-based C actions. Use tag-change triggers whenever possible. If a periodic refresh is required, use a VBScript that writes a single internal tag, and attach the C action to that tag with a 5-second or longer cycle.
  • Centralize the trigger tags. Create a set of internal tags such as Heartbeat_1s, Heartbeat_10s, and Heartbeat_1min in the internal tag list, and reference them from every action. Never use a raw process tag as a trigger for a complex C action.
  • Version-control the C actions. Export the global C actions as *.pas files (or the *.c / *.h source if the C-Editor was used) to a source-control system. A diff between two project versions will show every tag rename and every type change, and lets you spot the actions that have become stale.
  • Keep WinCC current. Apply the latest hotfix bundle for the installed major version. Siemens releases hotfixes for the C0000005 issue on a regular basis and the newest hotfix supersedes the previous ones.
  • Monitor the runtime. Use the CCDiagnostic.exe tool that ships with WinCC V7.x to monitor script.exe. A restart of script.exe more than once per hour is a strong indicator of a recurring access violation, even if the exception text has not yet been written to script.log.
  • Exclude WinCC directories from antivirus scans. Real-time antivirus scanning of the project directory, the script library, and the WinCC bin directory can lock DLLs at the moment script.exe tries to load them and produce a delayed C0000005 at the next symbol resolution. Add the project path, C:\Program Files (x86)\Siemens\WinCC, and the project database path to the antivirus exclusion list.

ApDiag Field Reference

ApDiag is the Application and Process Diagnosis tool for WinCC scripts. The most useful controls for this fault are:

Control Function
Action list Lists every C action and its current state (running, aborted, completed)
Trace filter Filters the trace by action name, trigger type, tag name, or picture name
Stack trace window Shows the function calls that were active when the action was dispatched
Counter panel Displays the number of dispatches per action since the trace was started; a counter that stops incrementing is a sign that the action is stuck
Tag value window Shows the value of the trigger tag at the moment the action fired

ApDiag is started from the WinCC project context. The trace files are written to <project>\Scripts\log\apdiag.log and are not deleted when the runtime is closed. Compare the latest trace with a known-good trace from a reference project to find the action that diverges.

Heap and Memory Model Notes

The Windows C runtime used by WinCC V6.2 / V7.0 SP3 is the static msvcrt.dll with the standard malloc / free allocator. The C-action interpreter allocates a value buffer for every call to a tag accessor, hands the buffer to the user code, and frees the buffer on return. The buffer size is determined by the data type of the tag:

Tag Data Type Buffer Size (bytes) Access Function
BOOL 1 GetTagBit
SINT / USINT 1 GetTagByte
INT / UINT / WORD 2 GetTagWord
DINT / UDINT / DWORD 4 GetTagDWord
REAL / FLOAT 4 GetTagFloat
DOUBLE / LREAL 8 GetTagDouble
CHAR (raw text) 1 to 256 GetTagChar
STRING (WinCC text ref) 256 GetTagChar

If a C action requests a different size than the one the tag actually has (for example, a request for a DWORD on a tag that has been changed to REAL), the buffer is the right size for the new type, but the action code reads it as the old type. The first two bytes of the buffer will be the lower half of the IEEE-754 single-precision value, and the next two bytes will be the upper half. When the action passes this buffer to a string function, the string function reads the raw bytes and may overrun the buffer if the upper bytes do not contain a zero terminator within the expected length. The wcsncpy crash is the most common result.

Why a 1-Second Timer Is the Worst Case

On a 1-second timer, the action is dispatched 86,400 times per day. Each dispatch allocates a value buffer of typically 4 to 256 bytes. Over 24 hours the runtime allocates between 1.3 MB and 86 MB of short-lived buffers through the same allocator. The Windows low-fragmentation heap (LFH) will reuse the freed blocks aggressively, and a use-after-free that is harmless on a low-frequency trigger becomes a crash on a 1-second trigger. The empirical rule from Siemens support is: do not use a timer trigger faster than 5 seconds for any C action that touches a string or a tag value. For pure housekeeping (counters, blinkers, heartbeats), use VBScript with the HMIRuntime object instead of C.

Restoring a Corrupt Project

If the project has been corrupted by a chain of C0000005 events, follow the recovery procedure:

  1. Stop the WinCC runtime and the WinCC Server service.
  2. Restore the most recent backup of the project directory. The backup must include the Grafic, Library, and Scripts subdirectories as well as the project database files.
  3. If no backup is available, use the Project Duplicator in the WinCC Explorer to clone the project to a new path, then re-import the picture tree from the source project one picture at a time.
  4. Re-link the actions one at a time. Re-link and re-test the project after every action is added. The action that triggers the crash is the one that contains the stale reference.
  5. Once the project runs cleanly, deploy the fix to the production server.
Safety: Always stop the WinCC runtime before restoring a project. Restoring over a running project can leave script.exe in an inconsistent state and produce a second, harder-to-diagnose fault on the next trigger.

FAQ

What does the WinCC exception code C0000005 ACCESS_VIOLATION mean?

It is the Windows structured exception code for EXCEPTION_ACCESS_VIOLATION, raised when the WinCC scripting engine reads or writes a memory address for which it has no permission. In WinCC it almost always means a stale tag handle, a freed string buffer, or a NULL pointer inside AKTSTEU.dll's tag value accessor.

Where do I find the script.log file for a WinCC C0000005 crash?

The file is at <project_path>\Scripts\log\script.log on the station where the runtime is running. The path is usually C:\Program Files (x86)\Siemens\WinCC\WinCCProjects\<project>\Scripts\log\script.log.

Can a 1-second timer trigger cause the C0000005 crash in WinCC?

Yes. A 1-second timer trigger on a C action is the most common cause of the C0000005 crash. The action is dispatched 86,400 times per day, the value buffer is allocated and freed on every dispatch, and the low-fragmentation heap reuses the freed block, which produces a use-after-free inside wcsncpy. Replace the timer trigger with a tag-change trigger, or increase the timer cycle to 5 seconds or longer.

Which WinCC hotfix resolves the script.exe C0000005 crash?

The hotfix depends on the installed WinCC major version: WinCC V6.2 SP3 Hotfix 14, WinCC V7.0 SP3 Hotfix 11, WinCC V7.2 Upd 1 + Hotfix 6, and WinCC V7.3 Upd 1 + Hotfix 4. The latest hotfix for the installed major version should be applied. Hotfixes are available from the Siemens Industry Online Support portal.

How do I run ApDiag to find the action that triggered the fault?

Start the WinCC runtime, then start ApDiag.exe from the WinCC Tools menu. Click Start Trace, let the runtime run until the next crash, then open the trace. The last action in the trace is the one that faulted. Compare its name and trigger type with the action list in the WinCC Explorer to find the source code that needs to be fixed.

Will VBScript actions also crash with C0000005?

VBScript actions run in a separate interpreter (the VBScript runtime from Windows Script Host) and do not use AKTSTEU.dll. The C0000005 access violation described in this article is specific to C actions. VBScript actions have their own error model and report errors through the WinCC diagnostic log with a VBScript error number, not a Windows exception code.

Is the C0000005 crash in script.exe a Windows fault or a WinCC fault?

It is a WinCC fault surfaced through the Windows structured exception handling. The exception is raised by the C runtime that backs the WinCC C action interpreter, not by Windows itself. The Windows event log only records the consequence; the script.log file contains the root cause.

Back to blog