CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Reposted on 2020-02-23
by CristiFati

Original Post

Original - Posted on 2019-05-18
by CristiFati



            
Present in both answers; Present only in the new answer; Present only in the old answer;

Listing [\[Python 3.Docs\]: ctypes - A foreign function library for Python](https://docs.python.org/3/library/ctypes.html#module-ctypes).
I must say that I wasn't able to reproduce the behavior (even without fixing the errors below), using either "regular" *Python* or *IPython*.

Current issues:
1. *dll\_ctypes\_test* expects a ***c\_out* pointer**, but your'e passing a plain ***c\_out* instance**. You should use *ctypes.byref*. Don't know why *CTypes* doesn't complain because of this 2. *C* and *Python* structure definitions don't match. One example is *arr* which contains an ***element* array** in *C*, and an ***element* pointer array** in *Python*. This is *Undefined Behavior*, the 2 must be in sync 3. You marked the export function as *\_\_stdcall*, but you're loading the *.dll* with *CDLL*. You should use *WinDLL*. But since you're on *64bit* (considering your paths), this doesn't make too much of a difference
Example:
<!-- language-all: c -->
*dll00.h*:
#pragma once
#if defined(_WIN32) # if defined DLL0_EXPORTS # define DLL00_EXPORT_API __declspec(dllexport) # else # define DLL00_EXPORT_API __declspec(dllimport) # endif #else # define DLL00_EXPORT_API #endif
#define ELEMENT_COUNT 1000 #define ARRAY_COUNT 50

typedef struct { double var0, var1, var2, var3, var4, var5, var6, var7, var8, var9; } Element;

typedef struct { int size; Element data[ELEMENT_COUNT]; } Array1D;

typedef struct { int size; Array1D data[ARRAY_COUNT]; } Array2D;

#if defined(__cplusplus) extern "C" { #endif
DLL00_EXPORT_API void __stdcall dll00Func00(double in, Array2D *pOut);
#if defined(__cplusplus) } #endif

*dll00.c*:
#define DLL0_EXPORTS #include "dll0.h"
#include <stdio.h>

void dll00Func00(double in, Array2D *pOut) { if (pOut == NULL) { printf("From C - NULL array passed\n"); return; }; Array2D arr2d; printf("From C - Outer array size: %d\n", pOut->size); }

*code00.py*:
<!-- language: python -->
#!/usr/bin/env python
import sys import ctypes as ct

ELEMENT_COUNT = 1000 ARRAY_COUNT = 50

class Element(ct.Structure): _fields_ = [ ("var0", ct.c_double), ("var1", ct.c_double), ("var2", ct.c_double), ("var3", ct.c_double), ("var4", ct.c_double), ("var5", ct.c_double), ("var6", ct.c_double), ("var7", ct.c_double), ("var8", ct.c_double), ("var9", ct.c_double), ]

class Array1D(ct.Structure): _fields_ = [ ("size", ct.c_int), ("data", Element * ELEMENT_COUNT), ]

class Array2D(ct.Structure): _fields_ = [ ("size", ct.c_int), ("data", Array1D * ARRAY_COUNT), ]

DLL0_NAME = "./dll00.dll"

def main(*argv): dll0 = ct.WinDLL(DLL0_NAME) dll00Func00 = dll0.dll00Func00 dll00Func00.argtypes = [ct.c_double, ct.POINTER(Array2D)] #dll00Func00.argtypes = [ct.c_double, Array2D] # !!! Defining the 2nd argument whitout POINTER, triggers the error !!!
mat = Array2D() mat.size = 7 print("Array sizeof: {0:d} (0x{1:08X})".format(ct.sizeof(mat), ct.sizeof(mat)))
dll00Func00(5, ct.byref(mat)) #dll00Func00(5, mat)


if __name__ == "__main__": print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform)) main(*sys.argv[1:]) print("\nDone.")

**Output**:
<!-- language-all: lang-bat -->
> e:\Work\Dev\StackOverflow\q060297181>sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
> [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.20 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64'
> [prompt]> dir /b code00.py dll0.h dll00.c
> [prompt]> cl /nologo /MD /DDLL dll00.c /link /NOLOGO /DLL /OUT:dll00.dll dll00.c Creating library dll00.lib and object dll00.exp
> [prompt]> dir /b code00.py dll0.h dll00.c dll00.dll dll00.exp dll00.lib dll00.obj
> [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32
> Array sizeof: 4000408 (0x003D0A98) From C - Outer array size: 7
> Done.

When calling a function or method (there are some exceptions, but those are irrelevant here), the stack (a special memory area) is used for storage. Common stuff being stored:
- Arguments (and return value), which represent data exchanged between the *caller* and the *callee* - Local variables (in the *callee*), which are neither static, nor explicitly allocated on the heap (via *malloc*, *new*, ...) - Other data (invisible to the programmer, like *Instruction Pointer*, ...)
As expected, the stack is limited, so it can store a maximum amount of data. When the amount of data needed to be stored exceeds the maximum, *Stack Overflow* occurs (the most common scenario for the occurrence is during recursion, when there are too many recurring calls that need to store too much data).
Maximum stack size is determined by each application build options, and defaults vary depending on compiler, *OS*, *etc*. From [\[MS.Docs\]: /STACK (Stack Allocations)](https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations) (**emphasis** is mine):
> The reserve value specifies the total stack allocation in virtual memory. For ARM, x86 and x64 machines, the **default stack size is 1 MB**.
As seen, *Array2D* takes nearly ***4 MiB*** (so it wouldn't fit if / when attempted to be stored on the stack). <br>As I specified in the comment (from *code00.py*), defining *dll00Func00*'s 2<sup>nd</sup> *argtype* **without *ct.POINTER*** triggers the error. Maybe there's such a typo in the code you're actually running?
Anyway, some general guidelines to avoid this error:
- Avoid passing (as arguments/ return type) large amounts of data by value: - Use pointers (or references in *C++*) - Allocate them dynamically (on the heap) - Make them static (less desirable as static data segment is also limited) - Make sure recursion doesn't go too deep (where applicable) - Increase ("manually") the stack size when building an application
Although you're familiar with the concepts, here's [\[Python 3.Docs\]: ctypes - A foreign function library for Python](https://docs.python.org/3/library/ctypes.html#module-ctypes).
*Python* code polling a memory area while the *C* code is running, implies more than one thread. <br>Here's an example.
*dll.c*:
<!-- language: c -->
#include <stdio.h> #include <Windows.h>
#if defined(_WIN32) # define DLL_EXPORT __declspec(dllexport) #else # define DLL_EXPORT #endif
#define PRINT_MSG_2XI(ARG0, ARG1) printf("From C - [%s] (%d) - [%s]: ARG0: 0x%016p, ARG1: %d\n", __FILE__, __LINE__, __FUNCTION__, ARG0, ARG1)

typedef struct Srtruct_ { int value; int sentinel; } Struct;

DLL_EXPORT int func0(Struct *ptr) { int counter = 0; if (!ptr) { return -1; } while (ptr->sentinel) { ptr->value++; counter++; PRINT_MSG_2XI(ptr, ptr->value); Sleep(200); } return counter; }

*code.py*:
<!-- language: python -->
#!/usr/bin/env python3
import sys import ctypes import time import threading

DLL_NAME = "./dll.dll"

class Struct(ctypes.Structure): _fields_ = [ ("value", ctypes.c_int), ("sentinel", ctypes.c_int), ]

def thread_func(func, arg0): ret = func(arg0) print("\nFrom Python - Function returned {:d}".format(ret))

def main(): dll = ctypes.CDLL(DLL_NAME) func0 = dll.func0 func0.argtypes = [ctypes.POINTER(Struct)] func0.restype = ctypes.c_int
data = Struct(30, 1) t = threading.Thread(target=thread_func, args=(func0, data,)) t.start() time.sleep(1) print("From Python - Monitored value: {:d}".format(data.value)) time.sleep(1) print("From Python - Monitored value: {:d}".format(data.value)) data.sentinel = 0 time.sleep(0.5)

if __name__ == "__main__": print("Python {:s} on {:s}\n".format(sys.version, sys.platform)) main() print("\nDone.")

**Output**:
<!-- language-all: lang-bat -->
> [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056197585]> sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
> [prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.11 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64'
> [prompt]> dir /b code.py dll.c
> [prompt]> cl /nologo /DDLL dll.c /link /NOLOGO /DLL /OUT:dll.dll dll.c Creating library dll.lib and object dll.exp
> [prompt]> dir /b code.py dll.c dll.dll dll.exp dll.lib dll.obj
> [prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32
> From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 31 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 32 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 33 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 34 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 35 From Python - Monitored value: 35 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 36 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 37 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 38 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 39 From C - [dll.c] (27) - [func0]: ARG0: 0x00000152EB84CE90, ARG1: 40 From Python - Monitored value: 40
> From Python - Function returned 10
> Done.

        
Present in both answers; Present only in the new answer; Present only in the old answer;