1.关于flask的追溯jsonify与json.dumps的一些追溯和思考
2.游戏版权侵权认定方法是怎样的?
3.MPL对源代码的定义
4.源码阅读忆丛(51)eBPF
5.sourcemap的认知与运用
关于flask的jsonify与json.dumps的一些追溯和思考
有一天,我遇到了一个服务器报警问题,游戏源码追踪错误栈时,追溯发现是游戏源码由于在使用 Flask 的 jsonify 函数时传入的字典中混入了 string 和 int 类型的键导致的。修改数据后,追溯我开始思考这一设计背后的游戏源码gutmann源码逻辑以及为何会如此设定。源码追溯路径指向 JSONDecoder、追溯flask.json.__init__.py 及 _dump_arg_defaults。游戏源码分析这部分源码,追溯我发现项目使用的游戏源码是继承自 Flask 的 JSONDecoder,稍作修改以兼容如 bson.ObjectId 和 datetime 等数据类型,追溯其主体基于标准库中的游戏源码 JSONEncoder。
进一步深入 JSONEncoder 的追溯源码,我发现 sort_keys 的游戏源码使用在 JSONEncoder._iterencode_dict 中。此时,追溯我开始思考是否可以修改为始终使用默认的 False,以确保 key 为纯字符串。然而,官方为何没有选择这一方案?我开始在 GitHub 上寻找答案,最终在 issue 中找到了线索。在 Python 2 中确实如我所想,但在 Python 3 中,设计发生了改变。大佬们解释了背后的理由。
深入思考后,我倾向于支持 Python 3 的设计选择。首先,明确数据处理逻辑(如是否排序)是至关重要的。这里,我认为 Flask 的默认设置为 False 是个错误,应该与标准库保持一致。其次,确保数据类型的一致性是动态语言的局限性之一,这也是我越来越偏爱 Go 的原因。
从工作角度来看,我得出以下思考:永远不要依赖传入的数据,务必进行验证,尤其是llvm源码编译windows在关键业务中。这不仅是对 Flask 设计的反思,也是对编程实践的提醒,强调了数据验证和明确数据处理逻辑的重要性。
游戏版权侵权认定方法是怎样的?
游戏版权侵权认定方法抽象法、过滤法以及对比法三大类。一般这三种方法是需要同时一应用的,若是最后对比后的结果,显示此游戏与其他已经存在的游戏相似度达到一定的比例,那么就构成游戏侵权了。一、游戏版权侵权认定方法是怎样的?
游戏版权侵权认定第一步是抽象法,即先把游戏中的思想抽象出来。第二步是过滤法,即把公有领域的东西过滤出去。如果相同之处属于公有领域的表达,原告并不享有著作权,即使相似也不构成侵权。第三步是对比法,即把思想和公有领域的内容过滤出去后,剩下的部分进行对比,内容相似则构成侵权。具体到游戏,法官需要对软件源代码、游戏整体及部分元素一一进行对比判断。
二、怎么算侵犯游戏版权
1、模仿游戏规则尚不能界定为侵权
游戏规则的相互模仿已经成为游戏界公开的秘密。
某种程度上说,模仿游戏规则会导致同质化游戏的产生,从而碾压原创网络游戏的市场份额。但游戏规则的完全创新是非常困难的,有些游戏的原创者已经很难追溯;不少人也提出游戏规则属于思想的范畴,而著作权法只保护思想的表达,不保护思想本身,因此游戏规则不属于《著作权法》的保护范畴。
2、角色、游戏的源码指令、音效等游戏元素:模仿需谨慎
游戏产品不是代码的简单拼合,文字、图案、音乐、角色是游戏不可或缺的组成部分。游戏中的文字、图案、音乐等可能构成文字作品、美术作品以及音乐作品,受到著作权法的保护。根据著作权法的规定,未经著作权人许可,复制、发行或者通过信息网络向公众传播作品的,属于侵权行为。
司法实践中有不少法院支持著作权人、认定模仿游戏文字、图案、音乐等构成侵权的案例。
3、源代码侵权:高度敏感
目前中国法院认定计算机软件侵权的标准为“接触 实质性相似”原则,具体而言就是从以下两个方面审查:
第一,侵权人是否曾接触过被侵权人享有著作权的作品;
第二,请求保护作品与被控侵权作品之间是否构成实质性相似。
在员工侵权案件中,“接触”往往较为容易判定,如果被侵权人提供侵权人和被侵权人劳动合同并说明侵权人在软件开发过程中的职责,或者提供证据说明软件已经公开发行或销售即可。
在“实质性相似”标准的判断上,考虑到计算机软件的性质,司法实践中在相似性比对过程中一般会采用“逐句对照法”(即将软件作品进行逐字逐句的对照)、“全部观念及感觉对照法”(即从两件软件作品的整体风格、特点、感官等方面是否相似出发)以及“三段论认定法”(即从软件的输入、输出是否存在相似性予以判断),具体的android获取应用源码比对因素主要有数据结构、功能设计、源代码、文件、工具名等。
防止源代码侵权,取证至关重要,权利人要注意及时做好证据保全措施。
游戏侵权主要是通过对比源代码的方式进行的,若是有不仅借鉴了游戏的模式,直接将游戏的思想也借鉴过来之后,进行代码编写出来的游戏,是很有可能会构成游戏侵权的。此时侵权方必须要停止游戏的发行,并且需要支付赔偿金。
MPL对源代码的定义
MPL许可证对源代码的定义包含了对作品进行修改最优先选择的形式,具体来说,它包括所有模块的所有源程序,接口的定义以及控制可执行作品安装和编译的原始程序。若源代码贡献者选择的源代码与初始源代码有显著不同,其也可被视为源代码的一部分。
MPL许可证的第三条特别规定了源代码修改的描述要求。所有再发布者必须提供一个专门的文件,详细记录对源代码程序的修改时间与方式,确保源代码的透明度与可追溯性。
在MPL许可证中,源代码不仅是指原始的源程序,还包括了接口定义和控制可执行作品安装与编译的原始程序。这一定义覆盖了源代码的完整范围,确保了作品的可修改性与灵活性。
MPL许可证对源代码的描述要求,旨在保证源代码的透明度与可追溯性。所有再发布者必须提供一个专门的文件,详细记录对源代码的修改时间与方式,以增强源代码的可读性和可维护性。
源代码的定义在MPL许可证中涵盖了所有模块的源程序、接口定义和控制可执行作品安装与编译的原始程序。这一定义强调了源代码的jvm原理源码学院灵活性与可修改性,确保了作品的透明度与可追溯性。
MPL许可证对源代码的描述要求旨在确保源代码的透明度与可追溯性。所有再发布者需要提供一个专门的文件,详细记录对源代码的修改时间与方式,以提升源代码的可读性与可维护性。
源码阅读忆丛()eBPF
eBPF:革新内核的瑞士军刀
eBPF的发展如火如荼,其势头正盛,似乎有潜力彻底重塑Linux内核的可能。初识eBPF,源于对复杂源码的渴望,Hotspot、V8等大型项目让人望而却步,于是选择了一款小巧且充满潜力的eBPF来探索。深入学习后发现,eBPF的内容丰富多样,不仅提供了强大的调试工具,还能深入探测性能,勾起了我浓厚的兴趣。
通过百度和阅读电子书《BPF之巅-洞悉Linux系统和应用性能》,我对eBPF的原理有了初步了解。书中的前五章着重介绍了eBPF的原理和技术,而后续章节则详细阐述了其工具的使用方法。这些工具的功能确实强大,但更多是在调试器层面的延展。我尤其对性能探测工具感到好奇,这促使我进一步深入研究。
对eBPF原理的兴趣驱使我追溯其发展脉络。从年eBPF的早期版本开始,我发现其基础架构已足够强大,足以替代iptables。从年到年,这个领域似乎并未取得显著进展,这可能是因为它被忽视了。
随着深入研究Linux 4.1版本(年发行),我浏览了samples/bpf和kernel/bpf目录下的源代码,重点分析了libbpf.c、bpf_load.c、core.c、syscall.c、verifier.c等关键文件。这些代码揭示了eBPF的加载和编译机制,包括在用户态标记并记录映射和函数调用,然后在内核态通过verifier.c的bpf_check(...)函数实现映射地址或函数地址的真实替换。至于代码的动态编译和优化,我选择跳过,因为涉及到的JIT等技术我已经较为熟悉。
在理解eBPF动态插桩和静态插桩技术的基础上,我回顾了Linux 2.6.版本(年)的trace静态插桩技术。这个版本的trace功能较为基础,主要记录函数调用地址,但提供快速写入功能,即使数据来不及读取也会被覆盖。然而,读取数据时需要比较所有CPU的环形缓冲区记录,找到最久的记录。虽然功能有限,但trace静态插桩在内核重要函数的调用跟踪中发挥了作用。
此外,我还研究了Linux 2.6.版本的kprobes动态插桩技术。kprobes提供了一种动态跟踪函数调用的方法,主要通过kernel/kprobes.c和arch/x/kernel/kprobes.c文件实现。reenter_kprobe函数处理调试中断时的重入问题,而kretprobe则将第二个CPU核单步执行,避免冲突。jprobe则通过插入代码改变程序流程,理论上避免了重入问题。
在回顾了这些源码后,我发现它们的难度并不高,结合网络资源,我能够顺利阅读并理解。我仅记录了当时重点思考的部分,这些部分涉及了源码的关键功能和实现细节。
sourcemap的认知与运用
在讨论sourcemap之前,我们首先需要了解编程语言的编译过程。
编译是将编程语言转换为可执行代码的过程。然而,可执行代码和源代码是完全不同的两种格式。如果在执行过程中出现错误,很难定位源代码编写过程中出现的问题。因此,现代编译器基本上都支持一种标准的可执行代码与源代码之间的映射,以特定格式将这种映射关系持久化存储到文件中。当程序执行出现问题时,根据堆栈信息使用映射文件逆向还原到源代码,可以清晰地、语义化地查找编写过程中的错误。
在常见的C Family languages中,这种可执行代码和源码之间映射的格式已经是一种标准化的东西了,称为DWARF。尽管在每个厂商应用的平台上产生的文件格式不尽相同,但它们内里遵循的映射格式都遵循了DWARF调试标准。
回到Web前端领域讨论这个问题,类似地,我们有sourcemap这个东西。或者我们应该称它为sourcemap调试格式标准。因为目前我们对sourcemap的格式都遵循了一定的标准,但在它的用途上,却出现了千差万别。
本文中讨论sourcemap的格式组成是没有意义的,sourcemap的格式应当是一种持续发展的标准,每当标准更新,自然会有健壮的工具帮助解读。理解sourcemap的格式对它的应用不会有太明显的帮助。
按照我的理解,最早sourcemap是为了协助JavaScript代码混淆(或者压缩)而产生的。框架的作者为了缩小代码体积、避免生产环境的JavaScript代码能被轻松地阅读,使用压缩、混淆工具对源码进行了处理。如果产生了问题,有sourcemap还能轻松地还原代码。但当时的sourcemap并不是web标准之一,这为今日的web前端工程化体系埋下了隐患。
在上一节中提到,sourcemap是一种“可执行代码”和源码之间的映射关系,那么只要是产生编译的地方,就应该会有sourcemap产生。
首先想到了Babel这个工具,它是应用最广泛的JavaScript编译器,接下来我们尝试一个示例:
接着,我们安装babel,指定sourcemap参数为inline,并对其进行转换,得到:
可以看到,转换后的代码和源码产生了很大的区别,并且sourcemap以注释的形式紧跟在可执行代码尾部,它的链接指向了一个data URL。
这么看就很容易了解到,sourcemap是一个基于之前的web标准拓展的功能,它只需要以固定的注释格式跟随在一个脚本文件的末尾即可。那么不同的浏览器厂商想要兼容这个标准,只需要加以识别这个格式即可。
但上文可以看出,data URL加在注释中,任何外部人员都可以轻易获得。因此在做代码转换时,可以将sourcemap生成到一个单独的文件中,一般是文件名加.map后缀,那么对应的sourcemap的地址也就变成:
sourcemap的这种设计方法并不是独一份的。例如在C Family Language的构建交付体系中,为了调试方便,对于测试环境交付的库、可执行代码,并不会将它们的"sourcemap"从可执行代码中分离出来。它们的执行环境和大部分JavaScript引擎一样,在调试断点或者Exception时,都能自动地载入"sourcemap"并且给出对应的源码栈信息。而在生产交付时,都会在构建时将"sourcemap"从库和可执行文件中提取出来单独保存。这样既减小了交付的产物体积,还能保证源码信息不被外部人员知晓。
既然sourcemap在逐渐地成为一个标准,那么自然就有配套的标准工具对这种格式进行解析。除了Chrome devtools自带的以外,还可以使用常见的库,接下来我们使用mozilla的source-map库,对刚才的代码进行一些还原的操作。
这是断点调试常见经常会碰到的场景,比如某个exception发生在了我们刚才代码的line 9; column 2; 即console.log的位置。那么我们可以这么做:
通过载入map文件,然后查找line 9 column 2对应的源代码位置可得:
然后我们去index.ts中的3行2列,正好是ts文件中的console.log
可以看到,sourcemap不仅记录了代码行列数,还记录了源文件的位置,那么不用翻sourcemap的manual也能说明,sourcemap也像其他编译系统一样,支持多个文件、库的代码映射的集成合并。这对于大型工程的构建十分有用,大型工程往往由数以千计万计的库和代码文件组成,在这种复杂的构建中,我们往往只想要获得有限几个产物。除了可执行代码,sourcemap的统一产出也有利于我们方便地追溯生产环境的问题。
mozilla的source-map标准库不止有查找映射位置的这个作用,更能直接还原代码。我们可以直接载入一个sourcemap文件,然后查看它对应了那些源代码文件,然后根据这些文件进行逐个还原内容:
由于我们只有一个,得到的输出是
在实际开发场景中,我们碰到的sourcemap运用比上面提到的情况复杂得多,但是问题又没有办法一一枚举,所以这里讨论一些常见的例子
前面就见过两种形式:dataURL放在JavaScript文件结尾的、和独立写入文件的。他们的形式是显而易见的,并且特点也能清楚地看出来。前者内联,增大了体积,但是降低了使用的门槛。后者独立,可以隐藏保存起来,非必要时不使用。
但在webpack这种打包构建工具中,对sourcemap做了更多更详细的定义,其基本分类的依据也遵循以下几个维度:
具体的规则可以翻阅webpack对应的文档,光靠脑子记是没办法的。
对库、预编译/转换的sourcemap处理
日常开发中,使用库或者预编译的组件是很常见的事,例如:
预编译文件的处理
像这些场景对工程的构建提出了比较多的要求。这里就针对常用的webpack做一个处理的展示,还是以前面的工程为例,我们的Typescript库导出了函数a,然后我们直接引用dist/index.js(而非src/index.ts)
然后我们通过webpack打包并且导出它的sourcemap
最后我们得到了./dist/demo.dist.js.map(名字有点诡异哈)
然后我们再通过刚才写的sourcemap工具进行还原看看:
可以看到,webpack默认情况下可以识别预编译的文件它的sourcemap,并且进行合理的目录转换,保证指向正确
那么我们如果删除预编译文件的sourcemap呢?我对a函数的库重新编译了一遍,并且不导出任何sourcemap,结果对引入的a函数库的文件还原就变成了
库的处理
如果a函数是从npm库引用的呢?我尝试了下把函数a放到了库中,然后将源码引用改成了
结果虽然node_modules中带了sourcemap,但是还原后并不是原本的ts代码
这时候需要对webpack进行配置,增加source-map-loader作为预处理,且不能排除node_modules目录:
然后再进行打包编译出来的map我们对其进行还原发现:
webpack成功帮我们提取了node_modules库中的sourcemap
本文主要阐述了sourcemap的基本知识,包含了几个方面: